Move image class computation to the CompilerDriver

Change-Id: Ia51cdc199cdeaf409755ab8da23323e204ce041e
diff --git a/src/common_test.h b/src/common_test.h
index 3baa77c..0c171a8 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -346,9 +346,11 @@
       }
     }
     class_linker_->FixupDexCaches(runtime_->GetResolutionMethod());
-    image_classes_.reset(new std::set<std::string>);
-    compiler_driver_.reset(new CompilerDriver(compiler_backend, instruction_set, true, 2, false,
-                                              image_classes_.get(), true, true));
+    compiler_driver_.reset(new CompilerDriver(compiler_backend, instruction_set,
+                                              true, new CompilerDriver::DescriptorSet,
+                                              2, false, true, true));
+    // We typically don't generate an image in unit tests, disable this optimization by default.
+    compiler_driver_->SetSupportBootImageFixup(false);
 
     // Create the heap thread pool so that the GC runs in parallel for tests. Normally, the thread
     // pool is created by the runtime.
@@ -389,7 +391,6 @@
     (*icu_cleanup_fn)();
 
     compiler_driver_.reset();
-    image_classes_.reset();
     STLDeleteElements(&opened_dex_files_);
 
     Runtime::Current()->GetHeap()->VerifyHeap();  // Check for heap corruption after the test
@@ -522,7 +523,6 @@
   // Owned by the runtime
   ClassLinker* class_linker_;
   UniquePtr<CompilerDriver> compiler_driver_;
-  UniquePtr<std::set<std::string> > image_classes_;
 
  private:
   std::vector<const DexFile*> opened_dex_files_;
diff --git a/src/compiler/driver/compiler_driver.cc b/src/compiler/driver/compiler_driver.cc
index 40cc483..186cf0d 100644
--- a/src/compiler/driver/compiler_driver.cc
+++ b/src/compiler/driver/compiler_driver.cc
@@ -324,8 +324,8 @@
 }
 
 CompilerDriver::CompilerDriver(CompilerBackend compiler_backend, InstructionSet instruction_set,
-                               bool image, size_t thread_count, bool support_debugging,
-                               const std::set<std::string>* image_classes,
+                               bool image, DescriptorSet* image_classes,
+                               size_t thread_count, bool support_debugging,
                                bool dump_stats, bool dump_timings)
     : compiler_backend_(compiler_backend),
       instruction_set_(instruction_set),
@@ -333,19 +333,20 @@
       compiled_classes_lock_("compiled classes lock"),
       compiled_methods_lock_("compiled method lock"),
       image_(image),
+      image_classes_(image_classes),
       thread_count_(thread_count),
       support_debugging_(support_debugging),
       start_ns_(0),
       stats_(new AOTCompilationStats),
       dump_stats_(dump_stats),
       dump_timings_(dump_timings),
-      image_classes_(image_classes),
       compiler_library_(NULL),
       compiler_(NULL),
       compiler_context_(NULL),
       jni_compiler_(NULL),
       compiler_enable_auto_elf_loading_(NULL),
-      compiler_get_method_code_addr_(NULL)
+      compiler_get_method_code_addr_(NULL),
+      support_boot_image_fixup_(true)
 {
   std::string compiler_so_name(MakeCompilerSoName(compiler_backend_));
   compiler_library_ = dlopen(compiler_so_name.c_str(), RTLD_LAZY);
@@ -380,7 +381,7 @@
 
   CHECK(!Runtime::Current()->IsStarted());
   if (!image_) {
-    CHECK(image_classes_ == NULL);
+    CHECK(image_classes_.get() == NULL);
   }
 }
 
@@ -576,20 +577,199 @@
 
 void CompilerDriver::PreCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
                                 ThreadPool& thread_pool, TimingLogger& timings) {
+  LoadImageClasses(timings);
+
   Resolve(class_loader, dex_files, thread_pool, timings);
 
   Verify(class_loader, dex_files, thread_pool, timings);
 
   InitializeClasses(class_loader, dex_files, thread_pool, timings);
+
+  UpdateImageClasses(timings);
 }
 
 bool CompilerDriver::IsImageClass(const char* descriptor) const {
-  if (image_classes_ == NULL) {
-    return false;
+  DCHECK(descriptor != NULL);
+  if (image_classes_.get() == NULL) {
+    return true;
   }
   return image_classes_->find(descriptor) != image_classes_->end();
 }
 
+static void ResolveExceptionsForMethod(MethodHelper* mh,
+    std::set<std::pair<uint16_t, const DexFile*> >& exceptions_to_resolve)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  const DexFile::CodeItem* code_item = mh->GetCodeItem();
+  if (code_item == NULL) {
+    return;  // native or abstract method
+  }
+  if (code_item->tries_size_ == 0) {
+    return;  // nothing to process
+  }
+  const byte* encoded_catch_handler_list = DexFile::GetCatchHandlerData(*code_item, 0);
+  size_t num_encoded_catch_handlers = DecodeUnsignedLeb128(&encoded_catch_handler_list);
+  for (size_t i = 0; i < num_encoded_catch_handlers; i++) {
+    int32_t encoded_catch_handler_size = DecodeSignedLeb128(&encoded_catch_handler_list);
+    bool has_catch_all = false;
+    if (encoded_catch_handler_size <= 0) {
+      encoded_catch_handler_size = -encoded_catch_handler_size;
+      has_catch_all = true;
+    }
+    for (int32_t j = 0; j < encoded_catch_handler_size; j++) {
+      uint16_t encoded_catch_handler_handlers_type_idx =
+          DecodeUnsignedLeb128(&encoded_catch_handler_list);
+      // Add to set of types to resolve if not already in the dex cache resolved types
+      if (!mh->IsResolvedTypeIdx(encoded_catch_handler_handlers_type_idx)) {
+        exceptions_to_resolve.insert(
+            std::pair<uint16_t, const DexFile*>(encoded_catch_handler_handlers_type_idx,
+                                                &mh->GetDexFile()));
+      }
+      // ignore address associated with catch handler
+      DecodeUnsignedLeb128(&encoded_catch_handler_list);
+    }
+    if (has_catch_all) {
+      // ignore catch all address
+      DecodeUnsignedLeb128(&encoded_catch_handler_list);
+    }
+  }
+}
+
+static bool ResolveCatchBlockExceptionsClassVisitor(mirror::Class* c, void* arg)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  std::set<std::pair<uint16_t, const DexFile*> >* exceptions_to_resolve =
+      reinterpret_cast<std::set<std::pair<uint16_t, const DexFile*> >*>(arg);
+  MethodHelper mh;
+  for (size_t i = 0; i < c->NumVirtualMethods(); ++i) {
+    mirror::AbstractMethod* m = c->GetVirtualMethod(i);
+    mh.ChangeMethod(m);
+    ResolveExceptionsForMethod(&mh, *exceptions_to_resolve);
+  }
+  for (size_t i = 0; i < c->NumDirectMethods(); ++i) {
+    mirror::AbstractMethod* m = c->GetDirectMethod(i);
+    mh.ChangeMethod(m);
+    ResolveExceptionsForMethod(&mh, *exceptions_to_resolve);
+  }
+  return true;
+}
+
+static bool RecordImageClassesVisitor(mirror::Class* klass, void* arg)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  CompilerDriver::DescriptorSet* image_classes =
+      reinterpret_cast<CompilerDriver::DescriptorSet*>(arg);
+  image_classes->insert(ClassHelper(klass).GetDescriptor());
+  return true;
+}
+
+// Make a list of descriptors for classes to include in the image
+void CompilerDriver::LoadImageClasses(TimingLogger& timings)
+      LOCKS_EXCLUDED(Locks::mutator_lock_) {
+  if (image_classes_.get() == NULL) {
+    return;
+  }
+
+  // Make a first class to load all classes explicitly listed in the file
+  Thread* self = Thread::Current();
+  ScopedObjectAccess soa(self);
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  typedef DescriptorSet::iterator It;  // TODO: C++0x auto
+  for (It it = image_classes_->begin(), end = image_classes_->end(); it != end;) {
+    std::string descriptor(*it);
+    SirtRef<mirror::Class> klass(self, class_linker->FindSystemClass(descriptor.c_str()));
+    if (klass.get() == NULL) {
+      image_classes_->erase(it++);
+      LOG(WARNING) << "Failed to find class " << descriptor;
+      Thread::Current()->ClearException();
+    } else {
+      ++it;
+    }
+  }
+
+  // Resolve exception classes referenced by the loaded classes. The catch logic assumes
+  // exceptions are resolved by the verifier when there is a catch block in an interested method.
+  // Do this here so that exception classes appear to have been specified image classes.
+  std::set<std::pair<uint16_t, const DexFile*> > unresolved_exception_types;
+  SirtRef<mirror::Class> java_lang_Throwable(self,
+                                     class_linker->FindSystemClass("Ljava/lang/Throwable;"));
+  do {
+    unresolved_exception_types.clear();
+    class_linker->VisitClasses(ResolveCatchBlockExceptionsClassVisitor,
+                               &unresolved_exception_types);
+    typedef std::set<std::pair<uint16_t, const DexFile*> >::const_iterator It;  // TODO: C++0x auto
+    for (It it = unresolved_exception_types.begin(),
+         end = unresolved_exception_types.end();
+         it != end; ++it) {
+      uint16_t exception_type_idx = it->first;
+      const DexFile* dex_file = it->second;
+      mirror::DexCache* dex_cache = class_linker->FindDexCache(*dex_file);
+      mirror:: ClassLoader* class_loader = NULL;
+      SirtRef<mirror::Class> klass(self, class_linker->ResolveType(*dex_file, exception_type_idx,
+                                                                   dex_cache, class_loader));
+      if (klass.get() == NULL) {
+        const DexFile::TypeId& type_id = dex_file->GetTypeId(exception_type_idx);
+        const char* descriptor = dex_file->GetTypeDescriptor(type_id);
+        LOG(FATAL) << "Failed to resolve class " << descriptor;
+      }
+      DCHECK(java_lang_Throwable->IsAssignableFrom(klass.get()));
+    }
+    // Resolving exceptions may load classes that reference more exceptions, iterate until no
+    // more are found
+  } while (!unresolved_exception_types.empty());
+
+  // We walk the roots looking for classes so that we'll pick up the
+  // above classes plus any classes them depend on such super
+  // classes, interfaces, and the required ClassLinker roots.
+  class_linker->VisitClasses(RecordImageClassesVisitor, image_classes_.get());
+
+  CHECK_NE(image_classes_->size(), 0U);
+  timings.AddSplit("LoadImageClasses");
+}
+
+static void MaybeAddToImageClasses(mirror::Class* klass, CompilerDriver::DescriptorSet* image_classes)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  while (!klass->IsObjectClass()) {
+    ClassHelper kh(klass);
+    const char* descriptor = kh.GetDescriptor();
+    std::pair<CompilerDriver::DescriptorSet::iterator, bool> result =
+        image_classes->insert(descriptor);
+    if (result.second) {
+      LOG(INFO) << "Adding " << descriptor << " to image classes";
+    } else {
+      return;
+    }
+    for (size_t i = 0; i < kh.NumDirectInterfaces(); ++i) {
+      MaybeAddToImageClasses(kh.GetDirectInterface(i), image_classes);
+    }
+    if (klass->IsArrayClass()) {
+      MaybeAddToImageClasses(klass->GetComponentType(), image_classes);
+    }
+    klass = klass->GetSuperClass();
+  }
+}
+
+void CompilerDriver::FindClinitImageClassesCallback(mirror::Object* object, void* arg) {
+  DCHECK(object != NULL);
+  DCHECK(arg != NULL);
+  CompilerDriver* compiler_driver = reinterpret_cast<CompilerDriver*>(arg);
+  MaybeAddToImageClasses(object->GetClass(), compiler_driver->image_classes_.get());
+}
+
+void CompilerDriver::UpdateImageClasses(TimingLogger& timings) {
+  if (image_classes_.get() == NULL) {
+    return;
+  }
+
+  // Update image_classes_ with classes for objects created by <clinit> methods.
+  Thread* self = Thread::Current();
+  const char* old_cause = self->StartAssertNoThreadSuspension("ImageWriter");
+  Heap* heap = Runtime::Current()->GetHeap();
+  // TODO: Image spaces only?
+  WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
+  heap->FlushAllocStack();
+  heap->GetLiveBitmap()->Walk(FindClinitImageClassesCallback, this);
+  self->EndAssertNoThreadSuspension(old_cause);
+  timings.AddSplit("UpdateImageClasses");
+}
+
 void CompilerDriver::RecordClassStatus(ClassReference ref, CompiledClass* compiled_class) {
   MutexLock mu(Thread::Current(), CompilerDriver::compiled_classes_lock_);
   compiled_classes_.Put(ref, compiled_class);
@@ -914,8 +1094,7 @@
   }
   bool compiling_boot = Runtime::Current()->GetHeap()->GetSpaces().size() == 1;
   if (compiling_boot) {
-    const bool kSupportBootImageFixup = true;
-    if (kSupportBootImageFixup) {
+    if (support_boot_image_fixup_) {
       MethodHelper mh(method);
       if (IsImageClass(mh.GetDeclaringClassDescriptor())) {
         // We can only branch directly to Methods that are resolved in the DexCache.
@@ -1617,10 +1796,13 @@
   "Ljava/io/ObjectStreamClass;",  // Calls to Class.forName -> java.io.FileDescriptor.
   "Ljava/io/ObjectStreamConstants;", // Instance of non-image class SerializablePermission.
   "Ljava/lang/ClassLoader$SystemClassLoader;", // Calls System.getProperty -> OsConstants.initConstants.
+  "Ljava/lang/HexStringParser;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
+  "Ljava/lang/ProcessManager;", // Calls Thread.currentThread.
   "Ljava/lang/Runtime;", // Calls System.getProperty -> OsConstants.initConstants.
   "Ljava/lang/System;", // Calls OsConstants.initConstants.
   "Ljava/math/BigDecimal;", // Calls native ... -> java.math.NativeBN.BN_new().
   "Ljava/math/BigInteger;", // Calls native ... -> java.math.NativeBN.BN_new().
+  "Ljava/math/Primality;", // Calls native ... -> java.math.NativeBN.BN_new().
   "Ljava/math/Multiplication;", // Calls native ... -> java.math.NativeBN.BN_new().
   "Ljava/net/InetAddress;", // Requires libcore.io.OsConstants.
   "Ljava/net/Inet4Address;", // Sub-class of InetAddress.
@@ -1629,23 +1811,57 @@
   "Ljava/nio/charset/Charset;", // Calls Charset.getDefaultCharset -> System.getProperty -> OsConstants.initConstants.
   "Ljava/nio/charset/CharsetICU;", // Sub-class of Charset.
   "Ljava/nio/charset/Charsets;", // Calls Charset.forName.
+  "Ljava/security/AlgorithmParameterGenerator;", // Calls OsConstants.initConstants.
+  "Ljava/security/KeyPairGenerator$KeyPairGeneratorImpl;", // Calls OsConstants.initConstants.
   "Ljava/security/KeyPairGenerator;", // Calls OsConstants.initConstants.
   "Ljava/security/Security;", // Tries to do disk IO for "security.properties".
+  "Ljava/security/spec/RSAKeyGenParameterSpec;", // java.math.NativeBN.BN_new()
   "Ljava/sql/Date;", // Calls OsConstants.initConstants.
+  "Ljava/sql/DriverManager;", // Calls OsConstants.initConstants.
+  "Ljava/sql/Time;", // Calls OsConstants.initConstants.
+  "Ljava/sql/Timestamp;", // Calls OsConstants.initConstants.
   "Ljava/util/Date;", // Calls Date.<init> -> System.currentTimeMillis -> OsConstants.initConstants.
+  "Ljava/util/ListResourceBundle;", // Calls OsConstants.initConstants.
   "Ljava/util/Locale;", // Calls System.getProperty -> OsConstants.initConstants.
+  "Ljava/util/PropertyResourceBundle;", // Calls OsConstants.initConstants.
+  "Ljava/util/ResourceBundle;", // Calls OsConstants.initConstants.
+  "Ljava/util/ResourceBundle$MissingBundle;", // Calls OsConstants.initConstants.
+  "Ljava/util/Scanner;", // regex.Pattern.compileImpl.
   "Ljava/util/SimpleTimeZone;", // Sub-class of TimeZone.
   "Ljava/util/TimeZone;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
   "Ljava/util/concurrent/ConcurrentHashMap$Segment;", // Calls Runtime.getRuntime().availableProcessors().
+  "Ljava/util/concurrent/ConcurrentSkipListMap;", // Calls OsConstants.initConstants.
+  "Ljava/util/concurrent/Exchanger;", // Calls OsConstants.initConstants.
+  "Ljava/util/concurrent/ForkJoinPool;", // Calls OsConstants.initConstants.
+  "Ljava/util/concurrent/LinkedTransferQueue;", // Calls OsConstants.initConstants.
+  "Ljava/util/concurrent/Phaser;", // Calls OsConstants.initConstants.
+  "Ljava/util/concurrent/ScheduledThreadPoolExecutor;", // Calls AtomicLong.VMSupportsCS8()
+  "Ljava/util/concurrent/SynchronousQueue;", // Calls OsConstants.initConstants.
+  "Ljava/util/concurrent/atomic/AtomicLong;", // Calls AtomicLong.VMSupportsCS8()
   "Ljava/util/logging/LogManager;", // Calls System.getProperty -> OsConstants.initConstants.
+  "Ljava/util/prefs/AbstractPreferences;", // Calls OsConstants.initConstants.
+  "Ljava/util/prefs/FilePreferencesImpl;", // Calls OsConstants.initConstants.
+  "Ljava/util/prefs/FilePreferencesFactoryImpl;", // Calls OsConstants.initConstants.
+  "Ljava/util/prefs/Preferences;", // Calls OsConstants.initConstants.
+  "Ljavax/crypto/KeyAgreement;", // Calls OsConstants.initConstants.
+  "Ljavax/crypto/KeyGenerator;", // Calls OsConstants.initConstants.
+  "Ljavax/security/cert/X509Certificate;", // Calls VMClassLoader.getBootClassPathSize.
+  "Ljavax/security/cert/X509Certificate$1;", // Calls VMClassLoader.getBootClassPathSize.
   "Ljavax/microedition/khronos/egl/EGL10;", // Requires EGLContext.
   "Ljavax/microedition/khronos/egl/EGLContext;", // Requires com.google.android.gles_jni.EGLImpl.
   "Ljavax/net/ssl/HttpsURLConnection;", // Calls SSLSocketFactory.getDefault -> java.security.Security.getProperty.
+  "Ljavax/xml/datatype/DatatypeConstants;", // Calls OsConstants.initConstants.
+  "Ljavax/xml/datatype/FactoryFinder;", // Calls OsConstants.initConstants.
+  "Ljavax/xml/namespace/QName;", // Calls OsConstants.initConstants.
+  "Ljavax/xml/validation/SchemaFactoryFinder;", // Calls OsConstants.initConstants.
+  "Ljavax/xml/xpath/XPathConstants;", // Calls OsConstants.initConstants.
+  "Ljavax/xml/xpath/XPathFactoryFinder;", // Calls OsConstants.initConstants.
   "Llibcore/icu/LocaleData;", // Requires java.util.Locale.
   "Llibcore/icu/TimeZoneNames;", // Requires java.util.TimeZone.
   "Llibcore/io/IoUtils;",  // Calls Random.<init> -> System.currentTimeMillis -> FileDescriptor -> OsConstants.initConstants.
   "Llibcore/io/OsConstants;", // Platform specific.
   "Llibcore/net/MimeUtils;", // Calls libcore.net.MimeUtils.getContentTypesPropertiesStream -> System.getProperty.
+  "Llibcore/reflect/Types;", // Calls OsConstants.initConstants.
   "Llibcore/util/ZoneInfo;", // Sub-class of TimeZone.
   "Llibcore/util/ZoneInfoDB;", // Calls System.getenv -> OsConstants.initConstants.
   "Lorg/apache/commons/logging/LogFactory;", // Calls System.getProperty.
@@ -1653,17 +1869,40 @@
   "Lorg/apache/harmony/security/provider/cert/X509CertFactoryImpl;", // Requires java.nio.charsets.Charsets.
   "Lorg/apache/harmony/security/provider/crypto/RandomBitsSupplier;", // Requires java.io.File.
   "Lorg/apache/harmony/security/utils/AlgNameMapper;", // Requires java.util.Locale.
+  "Lorg/apache/harmony/security/pkcs10/CertificationRequest;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/pkcs10/CertificationRequestInfo;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/pkcs7/AuthenticatedAttributes;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/pkcs7/SignedData;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/pkcs7/SignerInfo;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/pkcs8/PrivateKeyInfo;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/provider/crypto/SHA1PRNG_SecureRandomImpl;", // Calls OsConstants.initConstants.
   "Lorg/apache/harmony/security/x501/AttributeTypeAndValue;", // Calls IntegralToString.convertInt -> Thread.currentThread.
   "Lorg/apache/harmony/security/x501/DirectoryString;", // Requires BigInteger.
   "Lorg/apache/harmony/security/x501/Name;", // Requires org.apache.harmony.security.x501.AttributeTypeAndValue.
+  "Lorg/apache/harmony/security/x509/AccessDescription;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/x509/AuthorityKeyIdentifier;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/x509/CRLDistributionPoints;", // Calls Thread.currentThread.
   "Lorg/apache/harmony/security/x509/Certificate;", // Requires org.apache.harmony.security.x509.TBSCertificate.
-  "Lorg/apache/harmony/security/x509/TBSCertificate;",  // Requires org.apache.harmony.security.x501.Name.
+  "Lorg/apache/harmony/security/x509/CertificateIssuer;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/x509/CertificateList;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/x509/DistributionPoint;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/x509/DistributionPointName;", // Calls Thread.currentThread.
   "Lorg/apache/harmony/security/x509/EDIPartyName;", // Calls native ... -> java.math.NativeBN.BN_new().
   "Lorg/apache/harmony/security/x509/GeneralName;", // Requires org.apache.harmony.security.x501.Name.
   "Lorg/apache/harmony/security/x509/GeneralNames;", // Requires GeneralName.
+  "Lorg/apache/harmony/security/x509/GeneralSubtree;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/x509/GeneralSubtrees;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/x509/InfoAccessSyntax;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/x509/IssuingDistributionPoint;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/x509/NameConstraints;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/x509/TBSCertList$RevokedCertificate;", // Calls NativeBN.BN_new().
+  "Lorg/apache/harmony/security/x509/TBSCertList;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/x509/TBSCertificate;",  // Requires org.apache.harmony.security.x501.Name.
   "Lorg/apache/harmony/security/x509/Time;", // Calls native ... -> java.math.NativeBN.BN_new().
   "Lorg/apache/harmony/security/x509/Validity;", // Requires x509.Time.
+  "Lorg/apache/harmony/security/x509/tsp/TSTInfo;", // Calls Thread.currentThread.
   "Lorg/apache/harmony/xml/ExpatParser;", // Calls native ExpatParser.staticInitialize.
+  "Lorg/apache/harmony/xml/ExpatParser$EntityParser;", // Calls ExpatParser.staticInitialize.
   "Lorg/apache/http/conn/params/ConnRouteParams;", // Requires java.util.Locale.
   "Lorg/apache/http/conn/ssl/SSLSocketFactory;", // Calls java.security.Security.getProperty.
   "Lorg/apache/http/conn/util/InetAddressUtils;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
@@ -1693,6 +1932,9 @@
     // Only try to initialize classes that were successfully verified.
     if (klass->IsVerified()) {
       manager->GetClassLinker()->EnsureInitialized(klass, false, can_init_static_fields);
+      if (soa.Self()->IsExceptionPending()) {
+        soa.Self()->GetException(NULL)->Dump();
+      }
       if (!klass->IsInitialized()) {
         if (can_init_static_fields) {
           bool is_black_listed = false;
@@ -1730,7 +1972,7 @@
       compiled_class = new CompiledClass(status);
       manager->GetCompiler()->RecordClassStatus(ref, compiled_class);
     } else {
-      DCHECK_EQ(status, compiled_class->GetStatus());
+      DCHECK_GE(status, compiled_class->GetStatus()) << descriptor;
     }
   }
   // Clear any class not found or verification exceptions.
@@ -1854,7 +2096,8 @@
   } else if ((access_flags & kAccAbstract) != 0) {
   } else {
     // In small mode we only compile image classes.
-    bool dont_compile = Runtime::Current()->IsSmallMode() && ((image_classes_ == NULL) || (image_classes_->size() == 0));
+    bool dont_compile = (Runtime::Current()->IsSmallMode() &&
+                         ((image_classes_.get() == NULL) || (image_classes_->size() == 0)));
 
     // Don't compile class initializers, ever.
     if (((access_flags & kAccConstructor) != 0) && ((access_flags & kAccStatic) != 0)) {
diff --git a/src/compiler/driver/compiler_driver.h b/src/compiler/driver/compiler_driver.h
index 4f77bdb..fbfcadb 100644
--- a/src/compiler/driver/compiler_driver.h
+++ b/src/compiler/driver/compiler_driver.h
@@ -61,14 +61,16 @@
 
 class CompilerDriver {
  public:
+  typedef std::set<std::string> DescriptorSet;
+
   // Create a compiler targeting the requested "instruction_set".
   // "image" should be true if image specific optimizations should be
   // enabled.  "image_classes" lets the compiler know what classes it
   // can assume will be in the image, with NULL implying all available
   // classes.
-  explicit CompilerDriver(CompilerBackend compiler_backend, InstructionSet instruction_set, bool image,
+  explicit CompilerDriver(CompilerBackend compiler_backend, InstructionSet instruction_set,
+                          bool image, DescriptorSet* image_classes,
                           size_t thread_count, bool support_debugging,
-                          const std::set<std::string>* image_classes, 
                           bool dump_stats, bool dump_timings);
 
   ~CompilerDriver();
@@ -96,6 +98,10 @@
     return image_;
   }
 
+  DescriptorSet* GetImageClasses() const {
+    return image_classes_.get();
+  }
+
   CompilerTls* GetTls();
 
   // Generate the trampolines that are invoked by unresolved direct methods.
@@ -197,6 +203,15 @@
 
   void SetBitcodeFileName(std::string const& filename);
 
+  bool GetSupportBootImageFixup() const {
+    return support_boot_image_fixup_;
+  }
+
+  void SetSupportBootImageFixup(bool support_boot_image_fixup) {
+    support_boot_image_fixup_ = support_boot_image_fixup;
+  }
+
+
   // TODO: remove these Elf wrappers when libart links against LLVM (when separate compiler library is gone)
   bool WriteElf(const std::string& android_root,
                 bool is_host,
@@ -298,6 +313,8 @@
                   ThreadPool& thread_pool, TimingLogger& timings)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
 
+  void LoadImageClasses(TimingLogger& timings);
+
   // Attempt to resolve all type, methods, fields, and strings
   // referenced from code in the dex file following PathClassLoader
   // ordering semantics.
@@ -321,6 +338,10 @@
                          ThreadPool& thread_pool, TimingLogger& timings)
       LOCKS_EXCLUDED(Locks::mutator_lock_, compiled_classes_lock_);
 
+  void UpdateImageClasses(TimingLogger& timings);
+  static void FindClinitImageClassesCallback(mirror::Object* object, void* arg)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   void Compile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
                ThreadPool& thread_pool, TimingLogger& timings);
   void CompileDexFile(jobject class_loader, const DexFile& dex_file,
@@ -355,7 +376,13 @@
   mutable Mutex compiled_methods_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
   MethodTable compiled_methods_ GUARDED_BY(compiled_methods_lock_);
 
-  bool image_;
+  const bool image_;
+
+  // If image_ is true, specifies the classes that will be included in
+  // the image. Note if image_classes_ is NULL, all classes are
+  // included in the image.
+  UniquePtr<DescriptorSet> image_classes_;
+
   size_t thread_count_;
   bool support_debugging_;
   uint64_t start_ns_;
@@ -365,8 +392,6 @@
   bool dump_stats_;
   bool dump_timings_;
 
-  const std::set<std::string>* image_classes_;
-
   typedef void (*CompilerCallbackFn)(CompilerDriver& driver);
   typedef MutexLock* (*CompilerMutexLockFn)(CompilerDriver& driver);
 
@@ -395,6 +420,8 @@
       (const CompilerDriver& driver, const CompiledMethod* cm, const mirror::AbstractMethod* method);
   CompilerGetMethodCodeAddrFn compiler_get_method_code_addr_;
 
+  bool support_boot_image_fixup_;
+
   DISALLOW_COPY_AND_ASSIGN(CompilerDriver);
 };
 
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index 235c068..f678ee9 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -161,18 +161,15 @@
   }
 
 
-  // Make a list of descriptors for classes to include in the image
-  std::set<std::string>* GetImageClassDescriptors(const char* image_classes_filename)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  // Reads the class names (java.lang.Object) and returns as set of class descriptors (Ljava/lang/Object;)
+  CompilerDriver::DescriptorSet* ReadImageClasses(const char* image_classes_filename) {
     UniquePtr<std::ifstream> image_classes_file(new std::ifstream(image_classes_filename, std::ifstream::in));
     if (image_classes_file.get() == NULL) {
       LOG(ERROR) << "Failed to open image classes file " << image_classes_filename;
       return NULL;
     }
 
-    // Load all the classes specified in the file
-    ClassLinker* class_linker = runtime_->GetClassLinker();
-    Thread* self = Thread::Current();
+    UniquePtr<CompilerDriver::DescriptorSet> image_classes(new CompilerDriver::DescriptorSet);
     while (image_classes_file->good()) {
       std::string dot;
       std::getline(*image_classes_file.get(), dot);
@@ -180,51 +177,9 @@
         continue;
       }
       std::string descriptor(DotToDescriptor(dot.c_str()));
-      SirtRef<mirror::Class> klass(self, class_linker->FindSystemClass(descriptor.c_str()));
-      if (klass.get() == NULL) {
-        LOG(WARNING) << "Failed to find class " << descriptor;
-        Thread::Current()->ClearException();
-      }
+      image_classes->insert(descriptor);
     }
     image_classes_file->close();
-
-    // Resolve exception classes referenced by the loaded classes. The catch logic assumes
-    // exceptions are resolved by the verifier when there is a catch block in an interested method.
-    // Do this here so that exception classes appear to have been specified image classes.
-    std::set<std::pair<uint16_t, const DexFile*> > unresolved_exception_types;
-    SirtRef<mirror::Class> java_lang_Throwable(self,
-                                       class_linker->FindSystemClass("Ljava/lang/Throwable;"));
-    do {
-      unresolved_exception_types.clear();
-      class_linker->VisitClasses(ResolveCatchBlockExceptionsClassVisitor,
-                                 &unresolved_exception_types);
-      typedef std::set<std::pair<uint16_t, const DexFile*> >::const_iterator It;  // TODO: C++0x auto
-      for (It it = unresolved_exception_types.begin(),
-           end = unresolved_exception_types.end();
-           it != end; ++it) {
-        uint16_t exception_type_idx = it->first;
-        const DexFile* dex_file = it->second;
-        mirror::DexCache* dex_cache = class_linker->FindDexCache(*dex_file);
-        mirror:: ClassLoader* class_loader = NULL;
-        SirtRef<mirror::Class> klass(self, class_linker->ResolveType(*dex_file, exception_type_idx,
-                                                                     dex_cache, class_loader));
-        if (klass.get() == NULL) {
-          const DexFile::TypeId& type_id = dex_file->GetTypeId(exception_type_idx);
-          const char* descriptor = dex_file->GetTypeDescriptor(type_id);
-          LOG(FATAL) << "Failed to resolve class " << descriptor;
-        }
-        DCHECK(java_lang_Throwable->IsAssignableFrom(klass.get()));
-      }
-      // Resolving exceptions may load classes that reference more exceptions, iterate until no
-      // more are found
-    } while (!unresolved_exception_types.empty());
-
-    // We walk the roots looking for classes so that we'll pick up the
-    // above classes plus any classes them depend on such super
-    // classes, interfaces, and the required ClassLinker roots.
-    UniquePtr<ImageWriter::DescriptorSet> image_classes(new ImageWriter::DescriptorSet);
-    class_linker->VisitClasses(RecordImageClassesVisitor, image_classes.get());
-    CHECK_NE(image_classes->size(), 0U);
     return image_classes.release();
   }
 
@@ -236,7 +191,7 @@
                                       File* oat_file,
                                       const std::string& bitcode_filename,
                                       bool image,
-                                      const ImageWriter::DescriptorSet* image_classes,
+                                      UniquePtr<CompilerDriver::DescriptorSet>& image_classes,
                                       bool dump_stats,
                                       bool dump_timings)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -260,9 +215,9 @@
     UniquePtr<CompilerDriver> driver(new CompilerDriver(compiler_backend_,
                                                         instruction_set_,
                                                         image,
+                                                        image_classes.release(),
                                                         thread_count_,
                                                         support_debugging_,
-                                                        image_classes,
                                                         dump_stats,
                                                         dump_timings));
 
@@ -320,7 +275,6 @@
 
   bool CreateImageFile(const std::string& image_filename,
                        uintptr_t image_base,
-                       ImageWriter::DescriptorSet* image_classes,
                        const std::string& oat_filename,
                        const std::string& oat_location,
                        const CompilerDriver& compiler)
@@ -328,8 +282,8 @@
     uintptr_t oat_data_begin;
     {
       // ImageWriter is scoped so it can free memory before doing FixupElf
-      ImageWriter image_writer(image_classes);
-      if (!image_writer.Write(image_filename, image_base, oat_filename, oat_location, compiler)) {
+      ImageWriter image_writer(compiler);
+      if (!image_writer.Write(image_filename, image_base, oat_filename, oat_location)) {
         LOG(ERROR) << "Failed to create image file " << image_filename;
         return false;
       }
@@ -380,72 +334,6 @@
     return true;
   }
 
-  static void ResolveExceptionsForMethod(MethodHelper* mh,
-                           std::set<std::pair<uint16_t, const DexFile*> >& exceptions_to_resolve)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    const DexFile::CodeItem* code_item = mh->GetCodeItem();
-    if (code_item == NULL) {
-      return;  // native or abstract method
-    }
-    if (code_item->tries_size_ == 0) {
-      return;  // nothing to process
-    }
-    const byte* encoded_catch_handler_list = DexFile::GetCatchHandlerData(*code_item, 0);
-    size_t num_encoded_catch_handlers = DecodeUnsignedLeb128(&encoded_catch_handler_list);
-    for (size_t i = 0; i < num_encoded_catch_handlers; i++) {
-      int32_t encoded_catch_handler_size = DecodeSignedLeb128(&encoded_catch_handler_list);
-      bool has_catch_all = false;
-      if (encoded_catch_handler_size <= 0) {
-        encoded_catch_handler_size = -encoded_catch_handler_size;
-        has_catch_all = true;
-      }
-      for (int32_t j = 0; j < encoded_catch_handler_size; j++) {
-        uint16_t encoded_catch_handler_handlers_type_idx =
-            DecodeUnsignedLeb128(&encoded_catch_handler_list);
-        // Add to set of types to resolve if not already in the dex cache resolved types
-        if (!mh->IsResolvedTypeIdx(encoded_catch_handler_handlers_type_idx)) {
-          exceptions_to_resolve.insert(
-              std::pair<uint16_t, const DexFile*>(encoded_catch_handler_handlers_type_idx,
-                                                  &mh->GetDexFile()));
-        }
-        // ignore address associated with catch handler
-        DecodeUnsignedLeb128(&encoded_catch_handler_list);
-      }
-      if (has_catch_all) {
-        // ignore catch all address
-        DecodeUnsignedLeb128(&encoded_catch_handler_list);
-      }
-    }
-  }
-
-  static bool ResolveCatchBlockExceptionsClassVisitor(mirror::Class* c, void* arg)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    std::set<std::pair<uint16_t, const DexFile*> >* exceptions_to_resolve =
-        reinterpret_cast<std::set<std::pair<uint16_t, const DexFile*> >*>(arg);
-    MethodHelper mh;
-    for (size_t i = 0; i < c->NumVirtualMethods(); ++i) {
-      mirror::AbstractMethod* m = c->GetVirtualMethod(i);
-      mh.ChangeMethod(m);
-      ResolveExceptionsForMethod(&mh, *exceptions_to_resolve);
-    }
-    for (size_t i = 0; i < c->NumDirectMethods(); ++i) {
-      mirror::AbstractMethod* m = c->GetDirectMethod(i);
-      mh.ChangeMethod(m);
-      ResolveExceptionsForMethod(&mh, *exceptions_to_resolve);
-    }
-    return true;
-  }
-
-  static bool RecordImageClassesVisitor(mirror::Class* klass, void* arg)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    ImageWriter::DescriptorSet* image_classes = reinterpret_cast<ImageWriter::DescriptorSet*>(arg);
-    if (klass->IsArrayClass() || klass->IsPrimitive()) {
-      return true;
-    }
-    image_classes->insert(ClassHelper(klass).GetDescriptor());
-    return true;
-  }
-
   // Appends to dex_files any elements of class_path that it doesn't already
   // contain. This will open those dex files as necessary.
   static void OpenClassPathFiles(const std::string& class_path, std::vector<const DexFile*>& dex_files) {
@@ -929,7 +817,7 @@
 #endif // ART_SMALL_MODE
 
   Dex2Oat* p_dex2oat;
-  if (!Dex2Oat::Create(&p_dex2oat, options, compiler_backend, instruction_set, thread_count, 
+  if (!Dex2Oat::Create(&p_dex2oat, options, compiler_backend, instruction_set, thread_count,
                        support_debugging)) {
     LOG(ERROR) << "Failed to create dex2oat";
     return EXIT_FAILURE;
@@ -943,9 +831,9 @@
   ScopedObjectAccess soa(Thread::Current());
 
   // If --image-classes was specified, calculate the full list of classes to include in the image
-  UniquePtr<ImageWriter::DescriptorSet> image_classes(NULL);
+  UniquePtr<CompilerDriver::DescriptorSet> image_classes(NULL);
   if (image_classes_filename != NULL) {
-    image_classes.reset(dex2oat->GetImageClassDescriptors(image_classes_filename));
+    image_classes.reset(dex2oat->ReadImageClasses(image_classes_filename));
     if (image_classes.get() == NULL) {
       LOG(ERROR) << "Failed to create list of image classes from " << image_classes_filename;
       return EXIT_FAILURE;
@@ -1001,7 +889,7 @@
                                                                   oat_file.get(),
                                                                   bitcode_filename,
                                                                   image,
-                                                                  image_classes.get(),
+                                                                  image_classes,
                                                                   dump_stats,
                                                                   dump_timings));
 
@@ -1066,7 +954,6 @@
     Thread::Current()->TransitionFromRunnableToSuspended(kNative);
     bool image_creation_success = dex2oat->CreateImageFile(image_filename,
                                                            image_base,
-                                                           image_classes.get(),
                                                            oat_unstripped,
                                                            oat_location,
                                                            *compiler.get());
diff --git a/src/image_test.cc b/src/image_test.cc
index cd1a34f..0769e21 100644
--- a/src/image_test.cc
+++ b/src/image_test.cc
@@ -43,28 +43,19 @@
   {
     std::vector<uint8_t> oat_contents;
     {
+      jobject class_loader = NULL;
+      ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+      compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath());
+
       ScopedObjectAccess soa(Thread::Current());
-      std::vector<const DexFile*> dex_files;
-      dex_files.push_back(java_lang_dex_file_);
-      dex_files.push_back(conscrypt_file_);
       VectorOutputStream output_stream(tmp_elf.GetFilename(), oat_contents);
-      bool success_oat = OatWriter::Create(output_stream, dex_files, 0, 0, "",
-                                           *compiler_driver_.get());
+      bool success_oat = OatWriter::Create(output_stream, class_linker->GetBootClassPath(),
+                                           0, 0, "", *compiler_driver_.get());
       ASSERT_TRUE(success_oat);
 
-      // Force all system classes into memory
-      for (size_t dex_file_index = 0; dex_file_index < dex_files.size(); ++dex_file_index) {
-        const DexFile* dex_file = dex_files[dex_file_index];
-        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);
-          mirror::Class* klass = class_linker_->FindSystemClass(descriptor);
-          EXPECT_TRUE(klass != NULL) << descriptor;
-        }
-      }
       bool success_elf = compiler_driver_->WriteElf(GetTestAndroidRoot(),
                                                     !kIsTargetBuild,
-                                                    dex_files,
+                                                    class_linker->GetBootClassPath(),
                                                     oat_contents,
                                                     tmp_elf.GetFile());
       ASSERT_TRUE(success_elf);
@@ -77,10 +68,9 @@
   ScratchFile tmp_image;
   const uintptr_t requested_image_base = ART_BASE_ADDRESS;
   {
-    ImageWriter writer(NULL);
+    ImageWriter writer(*compiler_driver_.get());
     bool success_image = writer.Write(tmp_image.GetFilename(), requested_image_base,
-                                      tmp_oat->GetPath(), tmp_oat->GetPath(),
-                                      *compiler_driver_.get());
+                                      tmp_oat->GetPath(), tmp_oat->GetPath());
     ASSERT_TRUE(success_image);
     bool success_fixup = compiler_driver_->FixupElf(tmp_oat.get(), writer.GetOatDataBegin());
     ASSERT_TRUE(success_fixup);
@@ -102,6 +92,9 @@
     ASSERT_GE(sizeof(image_header) + space->Size(), static_cast<size_t>(file->GetLength()));
   }
 
+  ASSERT_TRUE(compiler_driver_->GetImageClasses() != NULL);
+  CompilerDriver::DescriptorSet image_classes(*compiler_driver_->GetImageClasses());
+
   // Need to delete the compiler since it has worker threads which are attached to runtime.
   compiler_driver_.reset();
 
@@ -149,7 +142,13 @@
     mirror::Class* klass = class_linker_->FindSystemClass(descriptor);
     EXPECT_TRUE(klass != NULL) << descriptor;
     EXPECT_LT(image_begin, reinterpret_cast<byte*>(klass)) << descriptor;
-    EXPECT_LT(reinterpret_cast<byte*>(klass), image_end) << descriptor;
+    if (image_classes.find(descriptor) != image_classes.end()) {
+      // image classes should be located before the end of the image.
+      EXPECT_LT(reinterpret_cast<byte*>(klass), image_end) << descriptor;
+    } else {
+      // non image classes should be in a space after the image.
+      EXPECT_GT(reinterpret_cast<byte*>(klass), image_end) << descriptor;
+    }
     EXPECT_EQ(*klass->GetRawLockWordAddress(), 0);  // address should have been removed from monitor
   }
 }
diff --git a/src/image_writer.cc b/src/image_writer.cc
index 4ba99fe..5a1ebbb 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -57,8 +57,7 @@
 bool ImageWriter::Write(const std::string& image_filename,
                         uintptr_t image_begin,
                         const std::string& oat_filename,
-                        const std::string& oat_location,
-                        const CompilerDriver& compiler_driver) {
+                        const std::string& oat_location) {
   CHECK(!image_filename.empty());
 
   CHECK_NE(image_begin, 0U);
@@ -114,10 +113,10 @@
   Thread::Current()->TransitionFromSuspendedToRunnable();
   size_t oat_loaded_size = 0;
   size_t oat_data_offset = 0;
-  compiler_driver.GetOatElfInformation(oat_file.get(), oat_loaded_size, oat_data_offset);
+  compiler_driver_.GetOatElfInformation(oat_file.get(), oat_loaded_size, oat_data_offset);
   CalculateNewObjectOffsets(oat_loaded_size, oat_data_offset);
   CopyAndFixupObjects();
-  PatchOatCodeAndMethods(compiler_driver);
+  PatchOatCodeAndMethods();
   Thread::Current()->TransitionFromRunnableToSuspended(kNative);
 
   UniquePtr<File> image_file(OS::OpenFile(image_filename.c_str(), true));
@@ -199,42 +198,21 @@
 }
 
 bool ImageWriter::IsImageClass(const Class* klass) {
-  if (image_classes_ == NULL) {
-    return true;
-  }
-  while (klass->IsArrayClass()) {
-    klass = klass->GetComponentType();
-  }
-  if (klass->IsPrimitive()) {
-    return true;
-  }
-  const std::string descriptor(ClassHelper(klass).GetDescriptor());
-  return image_classes_->find(descriptor) != image_classes_->end();
+  return compiler_driver_.IsImageClass(ClassHelper(klass).GetDescriptor());
 }
 
-
 struct NonImageClasses {
   ImageWriter* image_writer;
   std::set<std::string>* non_image_classes;
 };
 
 void ImageWriter::PruneNonImageClasses() {
-  if (image_classes_ == NULL) {
+  if (compiler_driver_.GetImageClasses() == NULL) {
     return;
   }
   Runtime* runtime = Runtime::Current();
   ClassLinker* class_linker = runtime->GetClassLinker();
 
-  // Update image_classes_ with classes for objects created by <clinit> methods.
-  Thread* self = Thread::Current();
-  const char* old_cause = self->StartAssertNoThreadSuspension("ImageWriter");
-  Heap* heap = Runtime::Current()->GetHeap();
-  // TODO: Image spaces only?
-  WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
-  heap->FlushAllocStack();
-  heap->GetLiveBitmap()->Walk(FindClinitImageClassesCallback, this);
-  self->EndAssertNoThreadSuspension(old_cause);
-
   // Make a list of classes we would like to prune.
   std::set<std::string> non_image_classes;
   NonImageClasses context;
@@ -275,28 +253,6 @@
   }
 }
 
-void ImageWriter::FindClinitImageClassesCallback(Object* object, void* arg) {
-  DCHECK(object != NULL);
-  DCHECK(arg != NULL);
-  ImageWriter* image_writer = reinterpret_cast<ImageWriter*>(arg);
-  Class* klass = object->GetClass();
-  while (klass->IsArrayClass()) {
-    klass = klass->GetComponentType();
-  }
-  if (klass->IsPrimitive()) {
-    return;
-  }
-  while (!klass->IsObjectClass()) {
-    ClassHelper kh(klass);
-    const char* descriptor = kh.GetDescriptor();
-    std::pair<DescriptorSet::iterator, bool> result = image_writer->image_classes_->insert(descriptor);
-    if (result.second) {
-      LOG(INFO) << "Adding " << descriptor << " to image classes";
-    }
-    klass = klass->GetSuperClass();
-  }
-}
-
 bool ImageWriter::NonImageClassesVisitor(Class* klass, void* arg) {
   NonImageClasses* context = reinterpret_cast<NonImageClasses*>(arg);
   if (!context->image_writer->IsImageClass(klass)) {
@@ -307,7 +263,7 @@
 
 void ImageWriter::CheckNonImageClassesRemoved()
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  if (image_classes_ == NULL) {
+  if (compiler_driver_.GetImageClasses() == NULL) {
     return;
   }
 
@@ -336,8 +292,10 @@
 }
 
 void ImageWriter::DumpImageClasses() {
+  CompilerDriver::DescriptorSet* image_classes = compiler_driver_.GetImageClasses();
+  CHECK(image_classes != NULL);
   typedef std::set<std::string>::const_iterator It;  // TODO: C++0x auto
-  for (It it = image_classes_->begin(), end = image_classes_->end(); it != end; ++it) {
+  for (It it = image_classes->begin(), end = image_classes->end(); it != end; ++it) {
     LOG(INFO) << " " << *it;
   }
 }
@@ -659,13 +617,13 @@
   return method;
 }
 
-void ImageWriter::PatchOatCodeAndMethods(const CompilerDriver& compiler) {
+void ImageWriter::PatchOatCodeAndMethods() {
   Thread* self = Thread::Current();
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   const char* old_cause = self->StartAssertNoThreadSuspension("ImageWriter");
 
   typedef std::vector<const CompilerDriver::PatchInformation*> Patches;
-  const Patches& code_to_patch = compiler.GetCodeToPatch();
+  const Patches& code_to_patch = compiler_driver_.GetCodeToPatch();
   for (size_t i = 0; i < code_to_patch.size(); i++) {
     const CompilerDriver::PatchInformation* patch = code_to_patch[i];
     AbstractMethod* target = GetTargetMethod(patch);
@@ -675,7 +633,7 @@
     SetPatchLocation(patch, reinterpret_cast<uint32_t>(GetOatAddress(code_offset)));
   }
 
-  const Patches& methods_to_patch = compiler.GetMethodsToPatch();
+  const Patches& methods_to_patch = compiler_driver_.GetMethodsToPatch();
   for (size_t i = 0; i < methods_to_patch.size(); i++) {
     const CompilerDriver::PatchInformation* patch = methods_to_patch[i];
     AbstractMethod* target = GetTargetMethod(patch);
diff --git a/src/image_writer.h b/src/image_writer.h
index 4628e5a..4507592 100644
--- a/src/image_writer.h
+++ b/src/image_writer.h
@@ -37,9 +37,8 @@
 // Write a Space built during compilation for use during execution.
 class ImageWriter {
  public:
-  typedef std::set<std::string> DescriptorSet;
-  explicit ImageWriter(DescriptorSet* image_classes)
-      : oat_file_(NULL), image_end_(0), image_begin_(NULL), image_classes_(image_classes),
+  explicit ImageWriter(const CompilerDriver& compiler_driver)
+      : compiler_driver_(compiler_driver), oat_file_(NULL), image_end_(0), image_begin_(NULL),
         oat_data_begin_(NULL), interpreter_to_interpreter_entry_offset_(0),
         interpreter_to_quick_entry_offset_(0), portable_resolution_trampoline_offset_(0),
         quick_resolution_trampoline_offset_(0) {}
@@ -49,8 +48,7 @@
   bool Write(const std::string& image_filename,
              uintptr_t image_begin,
              const std::string& oat_filename,
-             const std::string& oat_location,
-             const CompilerDriver& compiler_driver)
+             const std::string& oat_location)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
 
   uintptr_t GetOatDataBegin() {
@@ -132,8 +130,6 @@
 
   // Remove unwanted classes from various roots.
   void PruneNonImageClasses() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static void FindClinitImageClassesCallback(mirror::Object* object, void* arg)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static bool NonImageClassesVisitor(mirror::Class* c, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -172,12 +168,14 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Patches references in OatFile to expect runtime addresses.
-  void PatchOatCodeAndMethods(const CompilerDriver& compiler)
+  void PatchOatCodeAndMethods()
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void SetPatchLocation(const CompilerDriver::PatchInformation* patch, uint32_t value)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 
+  const CompilerDriver& compiler_driver_;
+
   // Map of Object to where it will be at runtime.
   SafeMap<const mirror::Object*, size_t> offsets_;
 
@@ -193,9 +191,6 @@
   // Beginning target image address for the output image.
   byte* image_begin_;
 
-  // Set of classes to be include in the image, or NULL for all.
-  DescriptorSet* image_classes_;
-
   // Beginning target oat address for the pointers from the output image to its oat file.
   const byte* oat_data_begin_;
 
diff --git a/src/oat_test.cc b/src/oat_test.cc
index c7c063a..29e2891 100644
--- a/src/oat_test.cc
+++ b/src/oat_test.cc
@@ -74,8 +74,8 @@
 #else
   CompilerBackend compiler_backend = kQuick;
 #endif
-  compiler_driver_.reset(new CompilerDriver(compiler_backend, kThumb2, false, 2, false,
-                                            NULL, true, true));
+  compiler_driver_.reset(new CompilerDriver(compiler_backend, kThumb2, false, NULL, 2, false,
+                                            true, true));
   jobject class_loader = NULL;
   if (compile) {
     compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath());