Improved ClassLoader support

Change-Id: I587c0fa439c64a0c947641b01c072149f480bf85
diff --git a/build/Android.test.mk b/build/Android.test.mk
index 325f076..ba76f27 100644
--- a/build/Android.test.mk
+++ b/build/Android.test.mk
@@ -28,7 +28,7 @@
   LOCAL_MODULE := $(notdir $(basename $(2:%.arm=%)))
   LOCAL_MODULE_TAGS := tests
   LOCAL_SRC_FILES := $(2)
-  LOCAL_CFLAGS := $(ART_CFLAGS)
+  LOCAL_CFLAGS := $(ART_CFLAGS) -UNDEBUG
   LOCAL_C_INCLUDES += $(ART_C_INCLUDES)
   LOCAL_SHARED_LIBRARIES := libarttest libartd
   ifeq ($(1),target)
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 78e2c31..0d7c1dc 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -49,13 +49,27 @@
   Class* object_array_class = AllocClass(java_lang_Class);
   CHECK(object_array_class != NULL);
 
-  // string and char[] are necessary so that FindClass can assign names to members
+  // String and char[] are necessary so that FindClass can assign names to members
   Class* java_lang_String = AllocClass(java_lang_Class);
   CHECK(java_lang_String != NULL);
+  java_lang_String->descriptor_ = "Ljava/lang/String;";
+  CHECK_LT(java_lang_String->object_size_, sizeof(String));
   java_lang_String->object_size_ = sizeof(String);
   Class* char_array_class = AllocClass(java_lang_Class);
   CHECK(char_array_class != NULL);
 
+  // Field and Method are necessary so that FindClass can link members
+  Class* java_lang_reflect_Field = AllocClass(java_lang_Class);
+  CHECK(java_lang_reflect_Field != NULL);
+  java_lang_reflect_Field->descriptor_ = "Ljava/lang/reflect/Field;";
+  CHECK_LT(java_lang_reflect_Field->object_size_, std::max(sizeof(StaticField), sizeof(InstanceField)));
+  java_lang_reflect_Field->object_size_ = std::max(sizeof(StaticField), sizeof(InstanceField));
+  Class* java_lang_reflect_Method = AllocClass(java_lang_Class);
+  java_lang_reflect_Method->descriptor_ = "Ljava/lang/reflect/Method;";
+  CHECK(java_lang_reflect_Method != NULL);
+  CHECK_LT(java_lang_reflect_Method->object_size_, sizeof(Method));
+  java_lang_reflect_Method->object_size_ = sizeof(Method);
+
   // create storage for root classes, save away our work so far
   class_roots_ = ObjectArray<Class>::Alloc(object_array_class, kClassRootsMax);
   class_roots_->Set(kJavaLangClass, java_lang_Class);
@@ -63,48 +77,58 @@
   class_roots_->Set(kObjectArrayClass, object_array_class);
   class_roots_->Set(kJavaLangString, java_lang_String);
   class_roots_->Set(kCharArrayClass, char_array_class);
+  class_roots_->Set(kJavaLangReflectField, java_lang_reflect_Field);
+  class_roots_->Set(kJavaLangReflectMethod, java_lang_reflect_Method);
   // now that these are registered, we can use AllocClass() and AllocObjectArray
 
   String::InitClasses(java_lang_String, char_array_class);
   // Now AllocString* can be used
 
   // setup boot_class_path_ now that we can use AllocObjectArray to
-  // DexCache instances
+  // create DexCache instances
   for (size_t i = 0; i != boot_class_path.size(); ++i) {
     AppendToBootClassPath(boot_class_path[i]);
   }
   // now we can use FindSystemClass, at least for non-arrays classes.
 
-  // run Object and Class to setup their dex_cache_ fields and register them in classes_.
+  // run Class, Field, and Method through FindSystemClass.
+  // this initializes their dex_cache_ fields and register them in classes_.
   // we also override their object_size_ values to accommodate the extra C++ fields.
-  Class* Object_class = FindSystemClass(java_lang_Object->GetDescriptor());
-  CHECK_EQ(java_lang_Object, Object_class);
-  CHECK_LE(java_lang_Object->object_size_, sizeof(Object));
-  java_lang_Object->object_size_ = sizeof(Object);
   Class* Class_class = FindSystemClass(java_lang_Class->GetDescriptor());
   CHECK_EQ(java_lang_Class, Class_class);
-  CHECK_LE(java_lang_Class->object_size_, sizeof(Class));
+  CHECK_LT(java_lang_Class->object_size_, sizeof(Class));
   java_lang_Class->object_size_ = sizeof(Class);
-
-  // set special sizes for these C++ extended classes (Field, Method, String).
-  // we also remember them in class_roots_ to construct them within ClassLinker
-  Class* java_lang_reflect_Field = FindSystemClass("Ljava/lang/reflect/Field;");
-  CHECK(java_lang_reflect_Field != NULL);
-  CHECK_LE(java_lang_reflect_Field->object_size_, std::max(sizeof(StaticField), sizeof(InstanceField)));
+  Class* Field_class = FindSystemClass(java_lang_reflect_Field->GetDescriptor());
+  CHECK_EQ(java_lang_reflect_Field, Field_class);
+  CHECK_LT(java_lang_reflect_Field->object_size_, std::max(sizeof(StaticField), sizeof(InstanceField)));
   java_lang_reflect_Field->object_size_ = std::max(sizeof(StaticField), sizeof(InstanceField));
-  class_roots_->Set(kJavaLangReflectField, java_lang_reflect_Field);
-
-  Class* java_lang_reflect_Method = FindSystemClass("Ljava/lang/reflect/Method;");
-  CHECK(java_lang_reflect_Method != NULL);
-  CHECK_LE(java_lang_reflect_Method->object_size_, sizeof(Method));
+  Class* Method_class = FindSystemClass(java_lang_reflect_Method->GetDescriptor());
+  CHECK_EQ(java_lang_reflect_Method, Method_class);
+  CHECK_LT(java_lang_reflect_Method->object_size_, sizeof(Method));
   java_lang_reflect_Method->object_size_ = sizeof(Method);
-  class_roots_->Set(kJavaLangReflectMethod, java_lang_reflect_Method);
 
-  Class* String_class = FindSystemClass("Ljava/lang/String;");
+  // Object and String just need more minimal setup, since they do not have extra C++ fields.
+  Class* Object_class = FindSystemClass(java_lang_Object->GetDescriptor());
+  CHECK_EQ(java_lang_Object, Object_class);
+  CHECK_EQ(java_lang_Object->object_size_, sizeof(Object));
+  Class* String_class = FindSystemClass(java_lang_String->GetDescriptor());
   CHECK_EQ(java_lang_String, String_class);
   CHECK_EQ(java_lang_String->object_size_, sizeof(String));
-  java_lang_String->object_size_ = sizeof(String);
-  class_roots_->Set(kJavaLangString, java_lang_String);
+
+  // Setup the ClassLoaders, adjusting the object_size_ as necessary
+  Class* java_lang_ClassLoader = FindSystemClass("Ljava/lang/ClassLoader;");
+  CHECK(java_lang_ClassLoader != NULL);
+  CHECK_LT(java_lang_ClassLoader->object_size_, sizeof(ClassLoader));
+  java_lang_ClassLoader->object_size_ = sizeof(ClassLoader);
+  class_roots_->Set(kJavaLangClassLoader, java_lang_ClassLoader);
+  Class* dalvik_system_BaseDexClassLoader = FindSystemClass("Ldalvik/system/BaseDexClassLoader;");
+  CHECK(dalvik_system_BaseDexClassLoader != NULL);
+  CHECK_EQ(dalvik_system_BaseDexClassLoader->object_size_, sizeof(BaseDexClassLoader));
+  class_roots_->Set(kDalvikSystemBaseDexClassLoader, dalvik_system_BaseDexClassLoader);
+  Class* dalvik_system_PathClassLoader = FindSystemClass("Ldalvik/system/PathClassLoader;");
+  CHECK(dalvik_system_PathClassLoader != NULL);
+  CHECK_EQ(dalvik_system_PathClassLoader->object_size_, sizeof(PathClassLoader));
+  class_roots_->Set(kDalvikSystemPathClassLoader, dalvik_system_PathClassLoader);
 
   // Setup a single, global copy of "interfaces" and "iftable" for
   // reuse across array classes
@@ -154,7 +178,7 @@
 
   // ensure all class_roots_ were initialized
   for (size_t i = 0; i < kClassRootsMax; i++) {
-      CHECK(class_roots_->Get(i) != NULL);
+    CHECK(GetClassRoot(static_cast<ClassRoot>(i)));
   }
 
   // disable the slow paths in FindClass and CreatePrimitiveClass now
@@ -188,27 +212,38 @@
 }
 
 Class* ClassLinker::AllocClass() {
-  return AllocClass(class_roots_->Get(kJavaLangClass));
+  return AllocClass(GetClassRoot(kJavaLangClass));
 }
 
 StaticField* ClassLinker::AllocStaticField() {
-  return down_cast<StaticField*>(Heap::AllocObject(class_roots_->Get(kJavaLangReflectField),
-                                                   sizeof(StaticField)));
+  return down_cast<StaticField*>(Object::Alloc(GetClassRoot(kJavaLangReflectField)));
 }
 
 InstanceField* ClassLinker::AllocInstanceField() {
-  return down_cast<InstanceField*>(Heap::AllocObject(class_roots_->Get(kJavaLangReflectField),
-                                                     sizeof(InstanceField)));
+  return down_cast<InstanceField*>(Object::Alloc(GetClassRoot(kJavaLangReflectField)));
 }
 
 Method* ClassLinker::AllocMethod() {
-  return down_cast<Method*>(Heap::AllocObject(class_roots_->Get(kJavaLangReflectMethod),
-                                              sizeof(Method)));
+  return down_cast<Method*>(Object::Alloc(GetClassRoot(kJavaLangReflectMethod)));
+}
+
+// TODO remove once we can use java.lang.Class.getSystemClassLoader
+PathClassLoader* ClassLinker::AllocPathClassLoader(std::vector<const DexFile*> dex_files) {
+  PathClassLoader* cl = down_cast<PathClassLoader*>(Object::Alloc(GetClassRoot(kDalvikSystemPathClassLoader)));
+  cl->SetClassPath(dex_files);
+  return cl;
 }
 
 Class* ClassLinker::FindClass(const StringPiece& descriptor,
-                              Object* class_loader,
-                              const DexFile* dex_file) {
+                              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* self = Thread::Current();
   DCHECK(self != NULL);
   CHECK(!self->IsExceptionPending());
@@ -217,31 +252,30 @@
   if (klass == NULL) {
     // Class is not yet loaded.
     if (descriptor[0] == '[') {
-      return CreateArrayClass(descriptor, class_loader, dex_file);
+      return CreateArrayClass(descriptor, class_loader);
     }
-    ClassPathEntry pair;
-    if (dex_file == NULL) {
-      pair = FindInBootClassPath(descriptor);
-    } else {
-      pair.first = dex_file;
-      pair.second = dex_file->FindClassDef(descriptor);
-    }
+    DexFile::ClassPath& class_path = ((class_loader != NULL) ? class_loader->GetClassPath() : boot_class_path_);
+    DexFile::ClassPathEntry pair = DexFile::FindInClassPath(descriptor, class_path);
     if (pair.second == NULL) {
-      LG << "Class " << descriptor << " not found";  // TODO: NoClassDefFoundError
+      LG << "Class " << descriptor << " not found in class loader " << class_loader;  // TODO: NoClassDefFoundError
       return NULL;
     }
-    const DexFile* dex_file = pair.first;
-    const DexFile::ClassDef* dex_class_def = pair.second;
-    DexCache* dex_cache = FindDexCache(dex_file);
+    const DexFile& dex_file = *pair.first;
+    const DexFile::ClassDef& dex_class_def = *pair.second;
+    DexCache* dex_cache = FindDexCache(pair.first);
     // Load the class from the dex file.
     if (!init_done_) {
       // finish up init of hand crafted class_roots_
       if (descriptor == "Ljava/lang/Object;") {
-        klass = class_roots_->Get(kJavaLangObject);
+        klass = GetClassRoot(kJavaLangObject);
       } else if (descriptor == "Ljava/lang/Class;") {
-        klass = class_roots_->Get(kJavaLangClass);
+        klass = GetClassRoot(kJavaLangClass);
       } else if (descriptor == "Ljava/lang/String;") {
-        klass = class_roots_->Get(kJavaLangString);
+        klass = GetClassRoot(kJavaLangString);
+      } else if (descriptor == "Ljava/lang/reflect/Field;") {
+        klass = GetClassRoot(kJavaLangReflectField);
+      } else if (descriptor == "Ljava/lang/reflect/Method;") {
+        klass = GetClassRoot(kJavaLangReflectMethod);
       } else {
         klass = AllocClass();
       }
@@ -249,7 +283,7 @@
       klass = AllocClass();
     }
     klass->dex_cache_ = dex_cache;
-    LoadClass(*dex_file, *dex_class_def, klass);
+    LoadClass(dex_file, dex_class_def, klass, class_loader);
     // Check for a pending exception during load
     if (self->IsExceptionPending()) {
       // TODO: free native allocations in klass
@@ -259,7 +293,7 @@
       ObjectLock lock(klass);
       klass->clinit_thread_id_ = self->GetId();
       // Add the newly loaded class to the loaded classes table.
-      bool success = InsertClass(klass);
+      bool success = InsertClass(klass); // TODO just return collision
       if (!success) {
         // We may fail to insert if we raced with another thread.
         klass->clinit_thread_id_ = 0;
@@ -267,13 +301,22 @@
         klass = LookupClass(descriptor, class_loader);
         CHECK(klass != NULL);
       } else {
-        // Link the class.
-        if (!LinkClass(klass, dex_file)) {
+        // Finish loading (if necessary) by finding parents
+        if (!klass->IsLoaded() && !LoadSuperAndInterfaces(klass, dex_file)) {
+          // Loading failed.
+          // TODO: CHECK(self->IsExceptionPending());
+          lock.NotifyAll();
+          return NULL;
+        }
+        CHECK(klass->IsLoaded());
+        // Link the class (if necessary)
+        if (!klass->IsLinked() && !LinkClass(klass, dex_file)) {
           // Linking failed.
           // TODO: CHECK(self->IsExceptionPending());
           lock.NotifyAll();
           return NULL;
         }
+        CHECK(klass->IsLinked());
       }
     }
   }
@@ -295,26 +338,29 @@
     return NULL;
   }
   // Return the loaded class.  No exceptions should be pending.
+  CHECK(klass->IsLinked());
   CHECK(!self->IsExceptionPending());
   return klass;
 }
 
 void ClassLinker::LoadClass(const DexFile& dex_file,
                             const DexFile::ClassDef& dex_class_def,
-                            Class* klass) {
+                            Class* klass,
+                            ClassLoader* class_loader) {
   CHECK(klass != NULL);
   CHECK(klass->dex_cache_ != NULL);
+  CHECK_EQ(Class::kStatusNotReady, klass->status_);
   const byte* class_data = dex_file.GetClassData(dex_class_def);
   DexFile::ClassDataHeader header = dex_file.ReadClassDataHeader(&class_data);
 
   const char* descriptor = dex_file.GetClassDescriptor(dex_class_def);
   CHECK(descriptor != NULL);
 
-  klass->klass_ = class_roots_->Get(kJavaLangClass);
+  klass->klass_ = GetClassRoot(kJavaLangClass);
   klass->descriptor_.set(descriptor);
   klass->descriptor_alloc_ = NULL;
   klass->access_flags_ = dex_class_def.access_flags_;
-  klass->class_loader_ = NULL;  // TODO
+  klass->class_loader_ = class_loader;
   klass->primitive_type_ = Class::kPrimNot;
   klass->status_ = Class::kStatusIdx;
 
@@ -415,7 +461,7 @@
                             Field* dst) {
   const DexFile::FieldId& field_id = dex_file.GetFieldId(src.field_idx_);
   dst->klass_ = klass;
-  dst->java_name_ = ResolveString(klass, field_id.name_idx_);
+  dst->java_name_ = ResolveString(klass, field_id.name_idx_, dex_file);
   dst->descriptor_.set(dex_file.dexStringByTypeIdx(field_id.type_idx_));
   dst->access_flags_ = src.access_flags_;
 }
@@ -426,7 +472,7 @@
                              Method* dst) {
   const DexFile::MethodId& method_id = dex_file.GetMethodId(src.method_idx_);
   dst->klass_ = klass;
-  dst->java_name_ = ResolveString(klass, method_id.name_idx_);
+  dst->java_name_ = ResolveString(klass, method_id.name_idx_, dex_file);
   {
     int32_t utf16_length;
     scoped_ptr<char> utf8(dex_file.CreateMethodDescriptor(method_id.proto_idx_,
@@ -455,17 +501,6 @@
   }
 }
 
-ClassLinker::ClassPathEntry ClassLinker::FindInBootClassPath(const StringPiece& descriptor) {
-  for (size_t i = 0; i != boot_class_path_.size(); ++i) {
-    const DexFile* dex_file = boot_class_path_[i];
-    const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor);
-    if (dex_class_def != NULL) {
-      return ClassPathEntry(dex_file, dex_class_def);
-    }
-  }
-  return ClassPathEntry(NULL, NULL);
-}
-
 void ClassLinker::AppendToBootClassPath(DexFile* dex_file) {
   CHECK(dex_file != NULL);
   boot_class_path_.push_back(dex_file);
@@ -484,19 +519,17 @@
   dex_caches_.push_back(dex_cache);
 }
 
-const DexFile* ClassLinker::FindDexFile(const DexCache* dex_cache) const {
-  CHECK(dex_cache != NULL);
+const DexFile& ClassLinker::FindDexFile(const DexCache* dex_cache) const {
   for (size_t i = 0; i != dex_caches_.size(); ++i) {
     if (dex_caches_[i] == dex_cache) {
-        return dex_files_[i];
+        return *dex_files_[i];
     }
   }
   CHECK(false) << "Could not find DexFile";
-  return NULL;
+  return *dex_files_[-1];
 }
 
 DexCache* ClassLinker::FindDexCache(const DexFile* dex_file) const {
-  CHECK(dex_file != NULL);
   for (size_t i = 0; i != dex_files_.size(); ++i) {
     if (dex_files_[i] == dex_file) {
         return dex_caches_[i];
@@ -533,178 +566,166 @@
 //
 // Returns NULL with an exception raised on failure.
 Class* ClassLinker::CreateArrayClass(const StringPiece& descriptor,
-                                     Object* class_loader,
-                                     const DexFile* dex_file)
+                                     ClassLoader* class_loader)
 {
-    CHECK(descriptor[0] == '[');
+  CHECK(descriptor[0] == '[');
 
-    // Identify the underlying element class and the array dimension depth.
-    Class* component_type_ = NULL;
-    int array_rank;
-    if (descriptor[1] == '[') {
-        // array of arrays; keep descriptor and grab stuff from parent
-        Class* outer = FindClass(descriptor.substr(1), class_loader, dex_file);
-        if (outer != NULL) {
-            // want the base class, not "outer", in our component_type_
-            component_type_ = outer->component_type_;
-            array_rank = outer->array_rank_ + 1;
-        } else {
-            DCHECK(component_type_ == NULL);  // make sure we fail
-        }
+  // Identify the underlying element class and the array dimension depth.
+  Class* component_type_ = NULL;
+  int array_rank;
+  if (descriptor[1] == '[') {
+    // array of arrays; keep descriptor and grab stuff from parent
+    Class* outer = FindClass(descriptor.substr(1), class_loader);
+    if (outer != NULL) {
+      // want the base class, not "outer", in our component_type_
+      component_type_ = outer->component_type_;
+      array_rank = outer->array_rank_ + 1;
     } else {
-        array_rank = 1;
-        if (descriptor[1] == 'L') {
-            // array of objects; strip off "[" and look up descriptor.
-            const StringPiece subDescriptor = descriptor.substr(1);
-            component_type_ = FindClass(subDescriptor, class_loader, dex_file);
-        } else {
-            // array of a primitive type
-            component_type_ = FindPrimitiveClass(descriptor[1]);
-        }
+      DCHECK(component_type_ == NULL);  // make sure we fail
     }
-
-    if (component_type_ == NULL) {
-        // failed
-        // DCHECK(Thread::Current()->IsExceptionPending());  // TODO
-        return NULL;
+  } else {
+    array_rank = 1;
+    if (descriptor[1] == 'L') {
+      // array of objects; strip off "[" and look up descriptor.
+      const StringPiece subDescriptor = descriptor.substr(1);
+      component_type_ = FindClass(subDescriptor, class_loader);
+    } else {
+      // array of a primitive type
+      component_type_ = FindPrimitiveClass(descriptor[1]);
     }
+  }
 
-    // See if the component type is already loaded.  Array classes are
-    // always associated with the class loader of their underlying
-    // element type -- an array of Strings goes with the loader for
-    // java/lang/String -- so we need to look for it there.  (The
-    // caller should have checked for the existence of the class
-    // before calling here, but they did so with *their* class loader,
-    // not the component type's loader.)
-    //
-    // If we find it, the caller adds "loader" to the class' initiating
-    // loader list, which should prevent us from going through this again.
-    //
-    // This call is unnecessary if "loader" and "component_type_->class_loader_"
-    // are the same, because our caller (FindClass) just did the
-    // lookup.  (Even if we get this wrong we still have correct behavior,
-    // because we effectively do this lookup again when we add the new
-    // class to the hash table --- necessary because of possible races with
-    // other threads.)
-    if (class_loader != component_type_->class_loader_) {
-        Class* new_class = LookupClass(descriptor, component_type_->class_loader_);
-        if (new_class != NULL) {
-            return new_class;
-        }
-    }
+  if (component_type_ == NULL) {
+    // failed
+    // DCHECK(Thread::Current()->IsExceptionPending());  // TODO
+    return NULL;
+  }
 
-    // Fill out the fields in the Class.
-    //
-    // It is possible to execute some methods against arrays, because
-    // all arrays are subclasses of java_lang_Object_, so we need to set
-    // up a vtable.  We can just point at the one in java_lang_Object_.
-    //
-    // Array classes are simple enough that we don't need to do a full
-    // link step.
-
-    Class* new_class = NULL;
-    if (!init_done_) {
-      if (descriptor == "[Ljava/lang/Object;") {
-        new_class = class_roots_->Get(kObjectArrayClass);
-        CHECK(new_class);
-      } else if (descriptor == "[C") {
-        new_class = class_roots_->Get(kCharArrayClass);
-        CHECK(new_class);
-      }
-    }
-    if (new_class == NULL) {
-      new_class = AllocClass();
-      if (new_class == NULL) {
-        return NULL;
-      }
-    }
-    new_class->descriptor_alloc_ = new std::string(descriptor.data(),
-                                                   descriptor.size());
-    new_class->descriptor_.set(new_class->descriptor_alloc_->data(),
-                               new_class->descriptor_alloc_->size());
-    Class* java_lang_Object = class_roots_->Get(kJavaLangObject);
-    new_class->super_class_ = java_lang_Object;
-    new_class->vtable_ = java_lang_Object->vtable_;
-    new_class->primitive_type_ = Class::kPrimNot;
-    new_class->component_type_ = component_type_;
-    new_class->class_loader_ = component_type_->class_loader_;
-    new_class->array_rank_ = array_rank;
-    new_class->status_ = Class::kStatusInitialized;
-    // don't need to set new_class->object_size_
-
-
-    // All arrays have java/lang/Cloneable and java/io/Serializable as
-    // interfaces.  We need to set that up here, so that stuff like
-    // "instanceof" works right.
-    //
-    // Note: The GC could run during the call to FindSystemClass,
-    // so we need to make sure the class object is GC-valid while we're in
-    // there.  Do this by clearing the interface list so the GC will just
-    // think that the entries are null.
-
-
-    // Use the single, global copies of "interfaces" and "iftable"
-    // (remember not to free them for arrays).
-    DCHECK(array_interfaces_ != NULL);
-    new_class->interfaces_ = array_interfaces_;
-    new_class->iftable_count_ = 2;
-    DCHECK(array_iftable_ != NULL);
-    new_class->iftable_ = array_iftable_;
-
-    // Inherit access flags from the component type.  Arrays can't be
-    // used as a superclass or interface, so we want to add "final"
-    // and remove "interface".
-    //
-    // Don't inherit any non-standard flags (e.g., kAccFinal)
-    // from component_type_.  We assume that the array class does not
-    // override finalize().
-    new_class->access_flags_ = ((new_class->component_type_->access_flags_ &
-                                 ~kAccInterface) | kAccFinal) & kAccJavaFlagsMask;
-
-    if (InsertClass(new_class)) {
+  // See if the component type is already loaded.  Array classes are
+  // always associated with the class loader of their underlying
+  // element type -- an array of Strings goes with the loader for
+  // java/lang/String -- so we need to look for it there.  (The
+  // caller should have checked for the existence of the class
+  // before calling here, but they did so with *their* class loader,
+  // not the component type's loader.)
+  //
+  // If we find it, the caller adds "loader" to the class' initiating
+  // loader list, which should prevent us from going through this again.
+  //
+  // This call is unnecessary if "loader" and "component_type_->class_loader_"
+  // are the same, because our caller (FindClass) just did the
+  // lookup.  (Even if we get this wrong we still have correct behavior,
+  // because we effectively do this lookup again when we add the new
+  // class to the hash table --- necessary because of possible races with
+  // other threads.)
+  if (class_loader != component_type_->class_loader_) {
+    Class* new_class = LookupClass(descriptor, component_type_->class_loader_);
+    if (new_class != NULL) {
       return new_class;
     }
-    // Another thread must have loaded the class after we
-    // started but before we finished.  Abandon what we've
-    // done.
-    //
-    // (Yes, this happens.)
+  }
 
-    // Grab the winning class.
-    Class* other_class = LookupClass(descriptor, component_type_->class_loader_);
-    DCHECK(other_class != NULL);
-    return other_class;
+  // Fill out the fields in the Class.
+  //
+  // It is possible to execute some methods against arrays, because
+  // all arrays are subclasses of java_lang_Object_, so we need to set
+  // up a vtable.  We can just point at the one in java_lang_Object_.
+  //
+  // Array classes are simple enough that we don't need to do a full
+  // link step.
+
+  Class* new_class = NULL;
+  if (!init_done_) {
+    if (descriptor == "[Ljava/lang/Object;") {
+      new_class = GetClassRoot(kObjectArrayClass);
+    } else if (descriptor == "[C") {
+      new_class = GetClassRoot(kCharArrayClass);
+    }
+  }
+  if (new_class == NULL) {
+    new_class = AllocClass();
+    if (new_class == NULL) {
+      return NULL;
+    }
+  }
+  new_class->descriptor_alloc_ = new std::string(descriptor.data(),
+                                                 descriptor.size());
+  new_class->descriptor_.set(new_class->descriptor_alloc_->data(),
+                             new_class->descriptor_alloc_->size());
+  Class* java_lang_Object = GetClassRoot(kJavaLangObject);
+  new_class->super_class_ = java_lang_Object;
+  new_class->vtable_ = java_lang_Object->vtable_;
+  new_class->primitive_type_ = Class::kPrimNot;
+  new_class->component_type_ = component_type_;
+  new_class->class_loader_ = component_type_->class_loader_;
+  new_class->array_rank_ = array_rank;
+  new_class->status_ = Class::kStatusInitialized;
+  // don't need to set new_class->object_size_
+
+
+  // All arrays have java/lang/Cloneable and java/io/Serializable as
+  // interfaces.  We need to set that up here, so that stuff like
+  // "instanceof" works right.
+  //
+  // Note: The GC could run during the call to FindSystemClass,
+  // so we need to make sure the class object is GC-valid while we're in
+  // there.  Do this by clearing the interface list so the GC will just
+  // think that the entries are null.
+
+
+  // Use the single, global copies of "interfaces" and "iftable"
+  // (remember not to free them for arrays).
+  DCHECK(array_interfaces_ != NULL);
+  new_class->interfaces_ = array_interfaces_;
+  new_class->iftable_count_ = 2;
+  DCHECK(array_iftable_ != NULL);
+  new_class->iftable_ = array_iftable_;
+
+  // Inherit access flags from the component type.  Arrays can't be
+  // used as a superclass or interface, so we want to add "final"
+  // and remove "interface".
+  //
+  // Don't inherit any non-standard flags (e.g., kAccFinal)
+  // from component_type_.  We assume that the array class does not
+  // override finalize().
+  new_class->access_flags_ = ((new_class->component_type_->access_flags_ &
+                               ~kAccInterface) | kAccFinal) & kAccJavaFlagsMask;
+
+  if (InsertClass(new_class)) {
+    return new_class;
+  }
+  // Another thread must have loaded the class after we
+  // started but before we finished.  Abandon what we've
+  // done.
+  //
+  // (Yes, this happens.)
+
+  // Grab the winning class.
+  Class* other_class = LookupClass(descriptor, component_type_->class_loader_);
+  DCHECK(other_class != NULL);
+  return other_class;
 }
 
 Class* ClassLinker::FindPrimitiveClass(char type) {
   switch (type) {
     case 'B':
-      DCHECK(class_roots_->Get(kPrimitiveByte) != NULL);
-      return class_roots_->Get(kPrimitiveByte);
+      return GetClassRoot(kPrimitiveByte);
     case 'C':
-      DCHECK(class_roots_->Get(kPrimitiveChar) != NULL);
-      return class_roots_->Get(kPrimitiveChar);
+      return GetClassRoot(kPrimitiveChar);
     case 'D':
-      DCHECK(class_roots_->Get(kPrimitiveDouble) != NULL);
-      return class_roots_->Get(kPrimitiveDouble);
+      return GetClassRoot(kPrimitiveDouble);
     case 'F':
-      DCHECK(class_roots_->Get(kPrimitiveFloat) != NULL);
-      return class_roots_->Get(kPrimitiveFloat);
+      return GetClassRoot(kPrimitiveFloat);
     case 'I':
-      DCHECK(class_roots_->Get(kPrimitiveInt) != NULL);
-      return class_roots_->Get(kPrimitiveInt);
+      return GetClassRoot(kPrimitiveInt);
     case 'J':
-      DCHECK(class_roots_->Get(kPrimitiveLong) != NULL);
-      return class_roots_->Get(kPrimitiveLong);
+      return GetClassRoot(kPrimitiveLong);
     case 'S':
-      DCHECK(class_roots_->Get(kPrimitiveShort) != NULL);
-      return class_roots_->Get(kPrimitiveShort);
+      return GetClassRoot(kPrimitiveShort);
     case 'Z':
-      DCHECK(class_roots_->Get(kPrimitiveBoolean) != NULL);
-      return class_roots_->Get(kPrimitiveBoolean);
+      return GetClassRoot(kPrimitiveBoolean);
     case 'V':
-      DCHECK(class_roots_->Get(kPrimitiveVoid) != NULL);
-      return class_roots_->Get(kPrimitiveVoid);
+      return GetClassRoot(kPrimitiveVoid);
     case 'L':
     case '[':
       LOG(ERROR) << "Not a primitive type " << static_cast<int>(type);
@@ -717,20 +738,22 @@
 bool ClassLinker::InsertClass(Class* klass) {
   // TODO: acquire classes_lock_
   const StringPiece& key = klass->GetDescriptor();
-  bool success = classes_.insert(std::make_pair(key, klass)).second;
+  Table::iterator it = classes_.insert(std::make_pair(key, klass));
+  return ((*it).second == klass);
   // TODO: release classes_lock_
-  return success;
 }
 
-Class* ClassLinker::LookupClass(const StringPiece& descriptor, Object* class_loader) {
+Class* ClassLinker::LookupClass(const StringPiece& descriptor, ClassLoader* class_loader) {
   // TODO: acquire classes_lock_
-  Table::iterator it = classes_.find(descriptor);
-  // TODO: release classes_lock_
-  if (it == classes_.end()) {
-    return NULL;
-  } else {
-    return (*it).second;
+  typedef Table::const_iterator It; // TODO: C++0x auto
+  for (It it = classes_.find(descriptor), end = classes_.end(); it != end; ++it) {
+    Class* klass = it->second;
+    if (klass->descriptor_ == descriptor && klass->class_loader_ == class_loader) {
+      return klass;
+    }
   }
+  return NULL;
+  // TODO: release classes_lock_
 }
 
 bool ClassLinker::InitializeClass(Class* klass) {
@@ -887,10 +910,10 @@
 bool ClassLinker::HasSameMethodDescriptorClasses(const Method* method,
                                                  const Class* klass1,
                                                  const Class* klass2) {
-  const DexFile* dex_file = FindDexFile(method->GetClass()->GetDexCache());
-  const DexFile::ProtoId& proto_id = dex_file->GetProtoId(method->proto_idx_);
+  const DexFile& dex_file = FindDexFile(method->GetClass()->GetDexCache());
+  const DexFile::ProtoId& proto_id = dex_file.GetProtoId(method->proto_idx_);
   DexFile::ParameterIterator *it;
-  for (it = dex_file->GetParameterIterator(proto_id); it->HasNext(); it->Next()) {
+  for (it = dex_file.GetParameterIterator(proto_id); it->HasNext(); it->Next()) {
     const char* descriptor = it->GetDescriptor();
     if (descriptor == NULL) {
       break;
@@ -903,7 +926,7 @@
     }
   }
   // Check the return type
-  const char* descriptor = dex_file->GetReturnTypeDescriptor(proto_id);
+  const char* descriptor = dex_file.GetReturnTypeDescriptor(proto_id);
   if (descriptor[0] == 'L' || descriptor[0] == '[') {
     if (HasSameDescriptorClasses(descriptor, klass1, klass2)) {
       return false;
@@ -939,14 +962,14 @@
 }
 
 bool ClassLinker::HasSameArgumentTypes(const Method* m1, const Method* m2) const {
-  const DexFile* dex1 = FindDexFile(m1->GetClass()->GetDexCache());
-  const DexFile* dex2 = FindDexFile(m2->GetClass()->GetDexCache());
-  const DexFile::ProtoId& proto1 = dex1->GetProtoId(m1->proto_idx_);
-  const DexFile::ProtoId& proto2 = dex2->GetProtoId(m2->proto_idx_);
+  const DexFile& dex1 = FindDexFile(m1->GetClass()->GetDexCache());
+  const DexFile& dex2 = FindDexFile(m2->GetClass()->GetDexCache());
+  const DexFile::ProtoId& proto1 = dex1.GetProtoId(m1->proto_idx_);
+  const DexFile::ProtoId& proto2 = dex2.GetProtoId(m2->proto_idx_);
 
   // TODO: compare ProtoId objects for equality and exit early
-  const DexFile::TypeList* type_list1 = dex1->GetProtoParameters(proto1);
-  const DexFile::TypeList* type_list2 = dex2->GetProtoParameters(proto2);
+  const DexFile::TypeList* type_list1 = dex1.GetProtoParameters(proto1);
+  const DexFile::TypeList* type_list2 = dex2.GetProtoParameters(proto2);
   size_t arity1 = (type_list1 == NULL) ? 0 : type_list1->Size();
   size_t arity2 = (type_list2 == NULL) ? 0 : type_list2->Size();
   if (arity1 != arity2) {
@@ -956,8 +979,8 @@
   for (size_t i = 0; i < arity1; ++i) {
     uint32_t type_idx1 = type_list1->GetTypeItem(i).type_idx_;
     uint32_t type_idx2 = type_list2->GetTypeItem(i).type_idx_;
-    const char* type1 = dex1->dexStringByTypeIdx(type_idx1);
-    const char* type2 = dex2->dexStringByTypeIdx(type_idx2);
+    const char* type1 = dex1.dexStringByTypeIdx(type_idx1);
+    const char* type2 = dex2.dexStringByTypeIdx(type_idx2);
     if (strcmp(type1, type2) != 0) {
       return false;
     }
@@ -967,12 +990,12 @@
 }
 
 bool ClassLinker::HasSameReturnType(const Method* m1, const Method* m2) const {
-  const DexFile* dex1 = FindDexFile(m1->GetClass()->GetDexCache());
-  const DexFile* dex2 = FindDexFile(m2->GetClass()->GetDexCache());
-  const DexFile::ProtoId& proto1 = dex1->GetProtoId(m1->proto_idx_);
-  const DexFile::ProtoId& proto2 = dex2->GetProtoId(m2->proto_idx_);
-  const char* type1 = dex1->dexStringByTypeIdx(proto1.return_type_idx_);
-  const char* type2 = dex2->dexStringByTypeIdx(proto2.return_type_idx_);
+  const DexFile& dex1 = FindDexFile(m1->GetClass()->GetDexCache());
+  const DexFile& dex2 = FindDexFile(m2->GetClass()->GetDexCache());
+  const DexFile::ProtoId& proto1 = dex1.GetProtoId(m1->proto_idx_);
+  const DexFile::ProtoId& proto2 = dex2.GetProtoId(m2->proto_idx_);
+  const char* type1 = dex1.dexStringByTypeIdx(proto1.return_type_idx_);
+  const char* type2 = dex2.dexStringByTypeIdx(proto2.return_type_idx_);
   return (strcmp(type1, type2) == 0);
 }
 
@@ -1007,15 +1030,15 @@
     return;
   }
   const StringPiece& descriptor = klass->GetDescriptor();
-  const DexFile* dex_file = FindDexFile(dex_cache);
-  const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor);
+  const DexFile& dex_file = FindDexFile(dex_cache);
+  const DexFile::ClassDef* dex_class_def = dex_file.FindClassDef(descriptor);
   CHECK(dex_class_def != NULL);
-  const byte* addr = dex_file->GetEncodedArray(*dex_class_def);
+  const byte* addr = dex_file.GetEncodedArray(*dex_class_def);
   size_t array_size = DecodeUnsignedLeb128(&addr);
   for (size_t i = 0; i < array_size; ++i) {
     StaticField* field = klass->GetStaticField(i);
     JValue value;
-    DexFile::ValueType type = dex_file->ReadEncodedValue(&addr, &value);
+    DexFile::ValueType type = dex_file.ReadEncodedValue(&addr, &value);
     switch (type) {
       case DexFile::kByte:
         field->SetByte(value.b);
@@ -1040,7 +1063,7 @@
         break;
       case DexFile::kString: {
         uint32_t string_idx = value.i;
-        String* resolved = ResolveString(klass, string_idx);
+        String* resolved = ResolveString(klass, string_idx, dex_file);
         field->SetObject(resolved);
         break;
       }
@@ -1056,14 +1079,8 @@
   }
 }
 
-bool ClassLinker::LinkClass(Class* klass, const DexFile* dex_file) {
-  CHECK(klass->status_ == Class::kStatusIdx ||
-        klass->status_ == Class::kStatusLoaded);
-  if (klass->status_ == Class::kStatusIdx) {
-    if (!LinkInterfaces(klass, dex_file)) {
-      return false;
-    }
-  }
+bool ClassLinker::LinkClass(Class* klass, const DexFile& dex_file) {
+  CHECK_EQ(Class::kStatusLoaded, klass->status_);
   if (!LinkSuperClass(klass)) {
     return false;
   }
@@ -1074,14 +1091,13 @@
     return false;
   }
   CreateReferenceOffsets(klass);
-  CHECK_EQ(klass->status_, Class::kStatusLoaded);
+  CHECK_EQ(Class::kStatusLoaded, klass->status_);
   klass->status_ = Class::kStatusResolved;
   return true;
 }
 
-bool ClassLinker::LinkInterfaces(Class* klass, const DexFile* dex_file) {
-  // Mark the class as loaded.
-  klass->status_ = Class::kStatusLoaded;
+bool ClassLinker::LoadSuperAndInterfaces(Class* klass, const DexFile& dex_file) {
+  CHECK_EQ(Class::kStatusIdx, klass->status_);
   if (klass->super_class_idx_ != DexFile::kDexNoIndex) {
     Class* super_class = ResolveClass(klass, klass->super_class_idx_, dex_file);
     if (super_class == NULL) {
@@ -1105,6 +1121,8 @@
       }
     }
   }
+  // Mark the class as loaded.
+  klass->status_ = Class::kStatusLoaded;
   return true;
 }
 
@@ -1125,15 +1143,15 @@
   }
   // Verify
   if (super->IsFinal()) {
-    LG << "Superclass is declared final";  // TODO: IncompatibleClassChangeError
+    LG << "Superclass " << super->descriptor_ << " is declared final";  // TODO: IncompatibleClassChangeError
     return false;
   }
   if (super->IsInterface()) {
-    LG << "Superclass is an interface";  // TODO: IncompatibleClassChangeError
+    LG << "Superclass " << super->descriptor_ << " is an interface";  // TODO: IncompatibleClassChangeError
     return false;
   }
   if (!klass->CanAccess(super)) {
-    LG << "Superclass is inaccessible";  // TODO: IllegalAccessError
+    LG << "Superclass " << super->descriptor_ << " is  inaccessible";  // TODO: IllegalAccessError
     return false;
   }
   return true;
@@ -1515,17 +1533,17 @@
 
 Class* ClassLinker::ResolveClass(const Class* referrer,
                                  uint32_t class_idx,
-                                 const DexFile* dex_file) {
+                                 const DexFile& dex_file) {
   DexCache* dex_cache = referrer->GetDexCache();
   Class* resolved = dex_cache->GetResolvedClass(class_idx);
   if (resolved != NULL) {
     return resolved;
   }
-  const char* descriptor = dex_file->dexStringByTypeIdx(class_idx);
+  const char* descriptor = dex_file.dexStringByTypeIdx(class_idx);
   if (descriptor[0] != '\0' && descriptor[1] == '\0') {
     resolved = FindPrimitiveClass(descriptor[0]);
   } else {
-    resolved = FindClass(descriptor, referrer->GetClassLoader(), dex_file);
+    resolved = FindClass(descriptor, referrer->GetClassLoader());
   }
   if (resolved != NULL) {
     Class* check = resolved->IsArray() ? resolved->component_type_ : resolved;
@@ -1549,11 +1567,11 @@
 }
 
 String* ClassLinker::ResolveString(const Class* referring,
-                                   uint32_t string_idx) {
-  const DexFile* dex_file = FindDexFile(referring->GetDexCache());
-  const DexFile::StringId& string_id = dex_file->GetStringId(string_idx);
-  int32_t utf16_length = dex_file->GetStringLength(string_id);
-  const char* utf8_data = dex_file->GetStringData(string_id);
+                                   uint32_t string_idx,
+                                   const DexFile& dex_file) {
+  const DexFile::StringId& string_id = dex_file.GetStringId(string_idx);
+  int32_t utf16_length = dex_file.GetStringLength(string_id);
+  const char* utf8_data = dex_file.GetStringData(string_id);
   String* new_string = String::AllocFromModifiedUtf8(utf16_length, utf8_data);
   // TODO: intern the new string
   referring->GetDexCache()->SetResolvedString(string_idx, new_string);
diff --git a/src/class_linker.h b/src/class_linker.h
index 87098c6..013196b 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -24,24 +24,25 @@
   ~ClassLinker() {}
 
   // Finds a class by its descriptor name.
-  // If dex_file is null, searches boot_class_path_.
+  // If class_loader is null, searches boot_class_path_.
   Class* FindClass(const StringPiece& descriptor,
-                   Object* class_loader,
-                   const DexFile* dex_file);
+                   ClassLoader* class_loader);
 
   Class* FindSystemClass(const StringPiece& descriptor) {
-    return FindClass(descriptor, NULL, NULL);
+    return FindClass(descriptor, NULL);
   }
 
   bool InitializeClass(Class* klass);
 
-  Class* LookupClass(const StringPiece& descriptor, Object* class_loader);
+  Class* LookupClass(const StringPiece& descriptor, ClassLoader* class_loader);
 
   Class* ResolveClass(const Class* referring,
                       uint32_t class_idx,
-                      const DexFile* dex_file);
+                      const DexFile& dex_file);
 
-  String* ResolveString(const Class* referring, uint32_t string_idx);
+  String* ResolveString(const Class* referring,
+                        uint32_t string_idx,
+                        const DexFile& dex_file);
 
   void RegisterDexFile(const DexFile* dex_file);
 
@@ -69,28 +70,25 @@
   ObjectArray<T>* AllocObjectArray(size_t length) {
     return ObjectArray<T>::Alloc(class_roots_->Get(kObjectArrayClass), length);
   }
+  PathClassLoader* AllocPathClassLoader(std::vector<const DexFile*> dex_files);
 
   Class* CreatePrimitiveClass(const StringPiece& descriptor);
 
   Class* CreateArrayClass(const StringPiece& descriptor,
-                          Object* class_loader,
-                          const DexFile* dex_file);
+                          ClassLoader* class_loader);
 
   Class* FindPrimitiveClass(char type);
 
-  const DexFile* FindDexFile(const DexCache* dex_cache) const;
+  const DexFile& FindDexFile(const DexCache* dex_cache) const;
 
   DexCache* FindDexCache(const DexFile* dex_file) const;
 
-  typedef std::pair<const DexFile*, const DexFile::ClassDef*> ClassPathEntry;
-
   void AppendToBootClassPath(DexFile* dex_file);
 
-  ClassPathEntry FindInBootClassPath(const StringPiece& descriptor);
-
   void LoadClass(const DexFile& dex_file,
                  const DexFile::ClassDef& dex_class_def,
-                 Class* klass);
+                 Class* klass,
+                 ClassLoader* class_loader);
 
   void LoadInterfaces(const DexFile& dex_file,
                       const DexFile::ClassDef& dex_class_def,
@@ -140,11 +138,11 @@
 
   bool HasSameArgumentTypes(const Method* m1, const Method* m2) const;
 
-  bool LinkClass(Class* klass, const DexFile* dex_file);
+  bool LinkClass(Class* klass, const DexFile& dex_file);
 
   bool LinkSuperClass(Class* klass);
 
-  bool LinkInterfaces(Class* klass, const DexFile* dex_file);
+  bool LoadSuperAndInterfaces(Class* klass, const DexFile& dex_file);
 
   bool LinkMethods(Class* klass);
 
@@ -164,8 +162,11 @@
 
   std::vector<DexCache*> dex_caches_;
 
+  // multimap from String::descriptor_ to Class* instances. Results
+  // should be compared for a matching Class::descriptor_ and
+  // Class::class_loader_.
   // TODO: unordered_multimap
-  typedef std::map<const StringPiece, Class*> Table;
+  typedef std::multimap<const StringPiece, Class*> Table;
 
   Table classes_;
 
@@ -174,12 +175,17 @@
   // TODO: classpath
 
   // indexes into class_roots_
-  enum ClassRoots {
+  enum ClassRoot {
     kJavaLangClass,
     kJavaLangObject,
+    kObjectArrayClass,
+    kJavaLangString,
+    kCharArrayClass,
     kJavaLangReflectField,
     kJavaLangReflectMethod,
-    kJavaLangString,
+    kJavaLangClassLoader,
+    kDalvikSystemBaseDexClassLoader,
+    kDalvikSystemPathClassLoader,
     kPrimitiveBoolean,
     kPrimitiveChar,
     kPrimitiveFloat,
@@ -189,17 +195,22 @@
     kPrimitiveInt,
     kPrimitiveLong,
     kPrimitiveVoid,
-    kObjectArrayClass,
-    kCharArrayClass,
     kClassRootsMax,
   };
   ObjectArray<Class>* class_roots_;
 
+  Class* GetClassRoot(ClassRoot class_root) {
+    Class* klass = class_roots_->Get(class_root);
+    DCHECK(klass != NULL);
+    return klass;
+  }
+
   ObjectArray<Class>* array_interfaces_;
   InterfaceEntry* array_iftable_;
 
   bool init_done_;
 
+  friend class RuntimeTest;
   FRIEND_TEST(ClassLinkerTest, ProtoCompare);
   FRIEND_TEST(ClassLinkerTest, ProtoCompare2);
   FRIEND_TEST(DexCacheTest, Open);
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index 8672cf9..d521183 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -23,6 +23,7 @@
     ASSERT_EQ(descriptor, primitive->GetDescriptor());
     EXPECT_TRUE(primitive->GetSuperClass() == NULL);
     EXPECT_FALSE(primitive->HasSuperClass());
+    EXPECT_TRUE(primitive->GetClassLoader() == NULL);
     EXPECT_TRUE(primitive->GetComponentType() == NULL);
     EXPECT_TRUE(primitive->GetStatus() == Class::kStatusInitialized);
     EXPECT_FALSE(primitive->IsErroneous());
@@ -44,8 +45,9 @@
 
   void AssertArrayClass(const StringPiece& array_descriptor,
                         int32_t array_rank,
-                        const StringPiece& component_type) {
-    Class* array = class_linker_->FindSystemClass(array_descriptor);
+                        const StringPiece& component_type,
+                        ClassLoader* class_loader) {
+    Class* array = class_linker_->FindClass(array_descriptor, class_loader);
     ASSERT_TRUE(array != NULL);
     ASSERT_TRUE(array->GetClass() != NULL);
     ASSERT_EQ(array->GetClass(), array->GetClass()->GetClass());
@@ -54,6 +56,7 @@
     EXPECT_TRUE(array->GetSuperClass() != NULL);
     EXPECT_EQ(class_linker_->FindSystemClass("Ljava/lang/Object;"), array->GetSuperClass());
     EXPECT_TRUE(array->HasSuperClass());
+    EXPECT_EQ(class_loader, array->GetClassLoader());
     ASSERT_TRUE(array->GetComponentType() != NULL);
     ASSERT_TRUE(array->GetComponentType()->GetDescriptor() != NULL);
     EXPECT_EQ(component_type, array->GetComponentType()->GetDescriptor());
@@ -75,18 +78,18 @@
     EXPECT_EQ(2U, array->NumInterfaces());
   }
 
-  void AssertDexFileClass(const DexFile* dex, const char* descriptor) {
+  void AssertDexFileClass(ClassLoader* class_loader, const char* descriptor) {
     ASSERT_TRUE(descriptor != NULL);
-    Class* klass = class_linker_->FindClass(descriptor, NULL, dex);
+    Class* klass = class_linker_->FindSystemClass(descriptor);
     ASSERT_TRUE(klass != NULL);
     EXPECT_EQ(descriptor, klass->GetDescriptor());
     if (klass->descriptor_ == "Ljava/lang/Object;") {
-        EXPECT_FALSE(klass->HasSuperClass());
+      EXPECT_FALSE(klass->HasSuperClass());
     } else {
-        EXPECT_TRUE(klass->HasSuperClass());
-        EXPECT_TRUE(klass->GetSuperClass() != NULL);
+      EXPECT_TRUE(klass->HasSuperClass());
+      EXPECT_TRUE(klass->GetSuperClass() != NULL);
     }
-    // EXPECT_TRUE(klass->GetClassLoader() != NULL);  // TODO needs class loader
+    EXPECT_EQ(class_loader, klass->GetClassLoader());
     EXPECT_TRUE(klass->GetDexCache() != NULL);
     EXPECT_TRUE(klass->GetComponentType() == NULL);
     EXPECT_TRUE(klass->GetComponentType() == NULL);
@@ -98,78 +101,78 @@
     EXPECT_TRUE(klass->IsInSamePackage(klass));
     EXPECT_TRUE(Class::IsInSamePackage(klass->GetDescriptor(), klass->GetDescriptor()));
     if (klass->IsInterface()) {
-        EXPECT_TRUE(klass->IsAbstract());
-        if (klass->NumDirectMethods() == 1) {
-            EXPECT_PRED2(String::EqualsUtf8, klass->GetDirectMethod(0)->GetName(), "<clinit>");
-        } else {
-            EXPECT_EQ(0U, klass->NumDirectMethods());
-        }
+      EXPECT_TRUE(klass->IsAbstract());
+      if (klass->NumDirectMethods() == 1) {
+        EXPECT_PRED2(String::EqualsUtf8, klass->GetDirectMethod(0)->GetName(), "<clinit>");
+      } else {
+        EXPECT_EQ(0U, klass->NumDirectMethods());
+      }
     } else {
-        if (!klass->IsSynthetic()) {
-            EXPECT_NE(0U, klass->NumDirectMethods());
-        }
+      if (!klass->IsSynthetic()) {
+        EXPECT_NE(0U, klass->NumDirectMethods());
+      }
     }
     if (klass->IsAbstract()) {
-        EXPECT_FALSE(klass->IsFinal());
+      EXPECT_FALSE(klass->IsFinal());
     } else {
-        EXPECT_FALSE(klass->IsAnnotation());
+      EXPECT_FALSE(klass->IsAnnotation());
     }
     if (klass->IsFinal()) {
-        EXPECT_FALSE(klass->IsAbstract());
-        EXPECT_FALSE(klass->IsAnnotation());
+      EXPECT_FALSE(klass->IsAbstract());
+      EXPECT_FALSE(klass->IsAnnotation());
     }
     if (klass->IsAnnotation()) {
-        EXPECT_FALSE(klass->IsFinal());
-        EXPECT_TRUE(klass->IsAbstract());
+      EXPECT_FALSE(klass->IsFinal());
+      EXPECT_TRUE(klass->IsAbstract());
     }
 
     EXPECT_FALSE(klass->IsPrimitive());
     EXPECT_TRUE(klass->CanAccess(klass));
 
     for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
-        Method* method = klass->GetDirectMethod(i);
-        EXPECT_TRUE(method != NULL);
+      Method* method = klass->GetDirectMethod(i);
+      EXPECT_TRUE(method != NULL);
     }
 
     for (size_t i = 0; i < klass->NumVirtualMethods(); i++) {
-        Method* method = klass->GetVirtualMethod(i);
-        EXPECT_TRUE(method != NULL);
+      Method* method = klass->GetVirtualMethod(i);
+      EXPECT_TRUE(method != NULL);
     }
 
     for (size_t i = 0; i < klass->NumInstanceFields(); i++) {
-        InstanceField* field = klass->GetInstanceField(i);
-        EXPECT_TRUE(field != NULL);
+      InstanceField* field = klass->GetInstanceField(i);
+      EXPECT_TRUE(field != NULL);
     }
 
     for (size_t i = 0; i < klass->NumStaticFields(); i++) {
-        StaticField* field = klass->GetStaticField(i);
-        EXPECT_TRUE(field != NULL);
+      StaticField* field = klass->GetStaticField(i);
+      EXPECT_TRUE(field != NULL);
     }
 
     // Confirm that all instances fields are packed together at the start
     EXPECT_GE(klass->NumInstanceFields(), klass->NumReferenceInstanceFields());
     for (size_t i = 0; i < klass->NumReferenceInstanceFields(); i++) {
-        InstanceField* field = klass->GetInstanceField(i);
-        ASSERT_TRUE(field != NULL);
-        ASSERT_TRUE(field->GetDescriptor() != NULL);
-        Class* fieldType = class_linker_->FindClass(field->GetDescriptor(), NULL, dex);
-        ASSERT_TRUE(fieldType != NULL);
-        EXPECT_FALSE(fieldType->IsPrimitive());
+      InstanceField* field = klass->GetInstanceField(i);
+      ASSERT_TRUE(field != NULL);
+      ASSERT_TRUE(field->GetDescriptor() != NULL);
+      Class* field_type = class_linker_->FindClass(field->GetDescriptor(), class_loader);
+      ASSERT_TRUE(field_type != NULL);
+      EXPECT_FALSE(field_type->IsPrimitive());
     }
     for (size_t i = klass->NumReferenceInstanceFields(); i < klass->NumInstanceFields(); i++) {
-        InstanceField* field = klass->GetInstanceField(i);
-        ASSERT_TRUE(field != NULL);
-        ASSERT_TRUE(field->GetDescriptor() != NULL);
-        Class* fieldType = class_linker_->FindClass(field->GetDescriptor(), NULL, dex);
-        ASSERT_TRUE(fieldType != NULL);
-        EXPECT_TRUE(fieldType->IsPrimitive());
+      InstanceField* field = klass->GetInstanceField(i);
+      ASSERT_TRUE(field != NULL);
+      ASSERT_TRUE(field->GetDescriptor() != NULL);
+      Class* field_type = class_linker_->FindClass(field->GetDescriptor(), class_loader);
+      ASSERT_TRUE(field_type != NULL);
+      EXPECT_TRUE(field_type->IsPrimitive());
     }
 
     size_t total_num_reference_instance_fields = 0;
     Class* k = klass;
     while (k != NULL) {
-        total_num_reference_instance_fields += k->NumReferenceInstanceFields();
-        k = k->GetSuperClass();
+      total_num_reference_instance_fields += k->NumReferenceInstanceFields();
+      k = k->GetSuperClass();
     }
     EXPECT_EQ(klass->GetReferenceOffsets() == 0,
               total_num_reference_instance_fields == 0);
@@ -179,13 +182,12 @@
     EXPECT_TRUE(root != NULL);
   }
 
-  void AssertDexFile(const DexFile* dex) {
+  void AssertDexFile(const DexFile* dex, ClassLoader* class_loader) {
     ASSERT_TRUE(dex != NULL);
-    class_linker_->RegisterDexFile(dex);
     for (size_t i = 0; i < dex->NumClassDefs(); i++) {
       const DexFile::ClassDef class_def = dex->GetClassDef(i);
       const char* descriptor = dex->GetClassDescriptor(class_def);
-      AssertDexFileClass(dex, descriptor);
+      AssertDexFileClass(class_loader, descriptor);
     }
     class_linker_->VisitRoots(TestRootVisitor, NULL);
   }
@@ -199,15 +201,15 @@
 }
 
 TEST_F(ClassLinkerTest, FindClassNested) {
-  scoped_ptr<DexFile> nested_dex(OpenDexFileBase64(kNestedDex));
-  class_linker_->RegisterDexFile(nested_dex.get());
+  scoped_ptr<DexFile> dex(OpenDexFileBase64(kNestedDex));
+  PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
 
-  Class* outer = class_linker_->FindClass("LNested;", NULL, nested_dex.get());
+  Class* outer = class_linker_->FindClass("LNested;", class_loader);
   ASSERT_TRUE(outer != NULL);
   EXPECT_EQ(0U, outer->NumVirtualMethods());
   EXPECT_EQ(1U, outer->NumDirectMethods());
 
-  Class* inner = class_linker_->FindClass("LNested$Inner;", NULL, nested_dex.get());
+  Class* inner = class_linker_->FindClass("LNested$Inner;", class_loader);
   ASSERT_TRUE(inner != NULL);
   EXPECT_EQ(0U, inner->NumVirtualMethods());
   EXPECT_EQ(1U, inner->NumDirectMethods());
@@ -235,6 +237,7 @@
   ASSERT_TRUE(JavaLangObject->GetDescriptor() == "Ljava/lang/Object;");
   EXPECT_TRUE(JavaLangObject->GetSuperClass() == NULL);
   EXPECT_FALSE(JavaLangObject->HasSuperClass());
+  EXPECT_TRUE(JavaLangObject->GetClassLoader() == NULL);
   EXPECT_TRUE(JavaLangObject->GetComponentType() == NULL);
   EXPECT_FALSE(JavaLangObject->IsErroneous());
   EXPECT_FALSE(JavaLangObject->IsVerified());
@@ -254,9 +257,9 @@
 
 
   scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassDex));
-  linker->RegisterDexFile(dex.get());
+  PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
   EXPECT_TRUE(linker->FindSystemClass("LMyClass;") == NULL);
-  Class* MyClass = linker->FindClass("LMyClass;", NULL, dex.get());
+  Class* MyClass = linker->FindClass("LMyClass;", class_loader);
   ASSERT_TRUE(MyClass != NULL);
   ASSERT_TRUE(MyClass->GetClass() != NULL);
   ASSERT_EQ(MyClass->GetClass(), MyClass->GetClass()->GetClass());
@@ -264,6 +267,7 @@
   ASSERT_TRUE(MyClass->GetDescriptor() == "LMyClass;");
   EXPECT_TRUE(MyClass->GetSuperClass() == JavaLangObject);
   EXPECT_TRUE(MyClass->HasSuperClass());
+  EXPECT_EQ(class_loader, MyClass->GetClassLoader());
   EXPECT_TRUE(MyClass->GetComponentType() == NULL);
   EXPECT_TRUE(MyClass->GetStatus() == Class::kStatusResolved);
   EXPECT_FALSE(MyClass->IsErroneous());
@@ -285,11 +289,11 @@
   EXPECT_EQ(JavaLangObject->GetClass()->GetClass(), MyClass->GetClass()->GetClass());
 
   // created by class_linker
-  AssertArrayClass("[C", 1, "C");
-  AssertArrayClass("[Ljava/lang/Object;", 1, "Ljava/lang/Object;");
+  AssertArrayClass("[C", 1, "C", NULL);
+  AssertArrayClass("[Ljava/lang/Object;", 1, "Ljava/lang/Object;", NULL);
   // synthesized on the fly
-  AssertArrayClass("[[C", 2, "C");
-  AssertArrayClass("[[[LMyClass;", 3, "LMyClass;");
+  AssertArrayClass("[[C", 2, "C", NULL);
+  AssertArrayClass("[[[LMyClass;", 3, "LMyClass;", class_loader);
   // or not available at all
   AssertNonExistantClass("[[[[LNonExistantClass;");
 }
@@ -297,10 +301,10 @@
 TEST_F(ClassLinkerTest, ProtoCompare) {
   ClassLinker* linker = class_linker_;
 
-  scoped_ptr<DexFile> proto_dex_file(OpenDexFileBase64(kProtoCompareDex));
-  linker->RegisterDexFile(proto_dex_file.get());
+  scoped_ptr<DexFile> dex(OpenDexFileBase64(kProtoCompareDex));
+  PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
 
-  Class* klass = linker->FindClass("LProtoCompare;", NULL, proto_dex_file.get());
+  Class* klass = linker->FindClass("LProtoCompare;", class_loader);
   ASSERT_TRUE(klass != NULL);
 
   ASSERT_EQ(4U, klass->NumVirtualMethods());
@@ -352,13 +356,13 @@
   ClassLinker* linker = class_linker_;
 
   scoped_ptr<DexFile> proto1_dex_file(OpenDexFileBase64(kProtoCompareDex));
-  linker->RegisterDexFile(proto1_dex_file.get());
+  PathClassLoader* class_loader_1 = AllocPathClassLoader(proto1_dex_file.get());
   scoped_ptr<DexFile> proto2_dex_file(OpenDexFileBase64(kProtoCompare2Dex));
-  linker->RegisterDexFile(proto2_dex_file.get());
+  PathClassLoader* class_loader_2 = AllocPathClassLoader(proto2_dex_file.get());
 
-  Class* klass1 = linker->FindClass("LProtoCompare;", NULL, proto1_dex_file.get());
+  Class* klass1 = linker->FindClass("LProtoCompare;", class_loader_1);
   ASSERT_TRUE(klass1 != NULL);
-  Class* klass2 = linker->FindClass("LProtoCompare2;", NULL, proto2_dex_file.get());
+  Class* klass2 = linker->FindClass("LProtoCompare2;", class_loader_2);
   ASSERT_TRUE(klass2 != NULL);
 
   Method* m1_1 = klass1->GetVirtualMethod(0);
@@ -393,9 +397,10 @@
 }
 
 TEST_F(ClassLinkerTest, LibCore) {
+  UseLibCoreDex();
   scoped_ptr<DexFile> libcore_dex_file(GetLibCoreDex());
-  EXPECT_TRUE(libcore_dex_file.get() != NULL); // Passes on host only until we have DexFile::OpenJar
-  AssertDexFile(libcore_dex_file.get());
+  EXPECT_TRUE(libcore_dex_file.get() != NULL);
+  AssertDexFile(libcore_dex_file.get(), NULL);
 }
 
 // C++ fields must exactly match the fields in the Java classes. If this fails,
@@ -403,18 +408,18 @@
 // ClassLinker::LinkInstanceFields.
 TEST_F(ClassLinkerTest, ValidateFieldOrderOfJavaCppUnionClasses) {
   UseLibCoreDex();
-  Class* string = class_linker_->FindClass( "Ljava/lang/String;", NULL, java_lang_dex_file_.get());
+  Class* string = class_linker_->FindSystemClass( "Ljava/lang/String;");
   ASSERT_EQ(4U, string->NumInstanceFields());
   EXPECT_PRED2(String::EqualsUtf8, string->GetInstanceField(0)->GetName(), "value");
   EXPECT_PRED2(String::EqualsUtf8, string->GetInstanceField(1)->GetName(), "hashCode");
   EXPECT_PRED2(String::EqualsUtf8, string->GetInstanceField(2)->GetName(), "offset");
   EXPECT_PRED2(String::EqualsUtf8, string->GetInstanceField(3)->GetName(), "count");
 
-  Class* accessible_object = class_linker_->FindClass("Ljava/lang/reflect/AccessibleObject;", NULL, java_lang_dex_file_.get());
+  Class* accessible_object = class_linker_->FindSystemClass("Ljava/lang/reflect/AccessibleObject;");
   ASSERT_EQ(1U, accessible_object->NumInstanceFields());
   EXPECT_PRED2(String::EqualsUtf8, accessible_object->GetInstanceField(0)->GetName(), "flag");
 
-  Class* field = class_linker_->FindClass("Ljava/lang/reflect/Field;", NULL, java_lang_dex_file_.get());
+  Class* field = class_linker_->FindSystemClass("Ljava/lang/reflect/Field;");
   ASSERT_EQ(6U, field->NumInstanceFields());
   EXPECT_PRED2(String::EqualsUtf8, field->GetInstanceField(0)->GetName(), "declaringClass");
   EXPECT_PRED2(String::EqualsUtf8, field->GetInstanceField(1)->GetName(), "genericType");
@@ -423,7 +428,7 @@
   EXPECT_PRED2(String::EqualsUtf8, field->GetInstanceField(4)->GetName(), "slot");
   EXPECT_PRED2(String::EqualsUtf8, field->GetInstanceField(5)->GetName(), "genericTypesAreInitialized");
 
-  Class* method = class_linker_->FindClass("Ljava/lang/reflect/Method;", NULL, java_lang_dex_file_.get());
+  Class* method = class_linker_->FindSystemClass("Ljava/lang/reflect/Method;");
   ASSERT_EQ(11U, method->NumInstanceFields());
   EXPECT_PRED2(String::EqualsUtf8, method->GetInstanceField( 0)->GetName(), "declaringClass");
   EXPECT_PRED2(String::EqualsUtf8, method->GetInstanceField( 1)->GetName(), "exceptionTypes");
@@ -436,6 +441,28 @@
   EXPECT_PRED2(String::EqualsUtf8, method->GetInstanceField( 8)->GetName(), "parameterTypes");
   EXPECT_PRED2(String::EqualsUtf8, method->GetInstanceField( 9)->GetName(), "genericTypesAreInitialized");
   EXPECT_PRED2(String::EqualsUtf8, method->GetInstanceField(10)->GetName(), "slot");
+
+  Class* class_loader = class_linker_->FindSystemClass("Ljava/lang/ClassLoader;");
+  ASSERT_EQ(2U, class_loader->NumInstanceFields());
+  EXPECT_PRED2(String::EqualsUtf8, class_loader->GetInstanceField(0)->GetName(), "packages");
+  EXPECT_PRED2(String::EqualsUtf8, class_loader->GetInstanceField(1)->GetName(), "parent");
+
+  Class* dex_base_class_loader = class_linker_->FindSystemClass("Ldalvik/system/BaseDexClassLoader;");
+  ASSERT_EQ(2U, dex_base_class_loader->NumInstanceFields());
+  EXPECT_PRED2(String::EqualsUtf8, dex_base_class_loader->GetInstanceField(0)->GetName(), "originalPath");
+  EXPECT_PRED2(String::EqualsUtf8, dex_base_class_loader->GetInstanceField(1)->GetName(), "pathList");
+}
+
+TEST_F(ClassLinkerTest, TwoClassLoadersOneClass) {
+  scoped_ptr<DexFile> dex_1(OpenDexFileBase64(kMyClassDex));
+  scoped_ptr<DexFile> dex_2(OpenDexFileBase64(kMyClassDex));
+  PathClassLoader* class_loader_1 = AllocPathClassLoader(dex_1.get());
+  PathClassLoader* class_loader_2 = AllocPathClassLoader(dex_2.get());
+  Class* MyClass_1 = class_linker_->FindClass("LMyClass;", class_loader_1);
+  Class* MyClass_2 = class_linker_->FindClass("LMyClass;", class_loader_2);
+  EXPECT_TRUE(MyClass_1 != NULL);
+  EXPECT_TRUE(MyClass_2 != NULL);
+  EXPECT_NE(MyClass_1, MyClass_2);
 }
 
 }  // namespace art
diff --git a/src/common_test.h b/src/common_test.h
index 685a06c..13f92d1 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -36,33 +36,57 @@
 // }
 //
 // package java.lang;
+// public class ClassLoader {
+//   Object packages;
+//   ClassLoader parent;
+// }
+//
+// package dalvik.system;
+// public class BaseDexClassLoader extends ClassLoader {
+//   String originalPath;
+//   Object pathList;
+// }
+//
+// package dalvik.system;
+// public class PathClassLoader extends BaseDexClassLoader {}
+//
+// package java.lang;
 // public interface Cloneable {}
 //
 // package java.io;
 // public interface Serializable {}
 static const char kJavaLangDex[] =
-  "ZGV4CjAzNQDgopvWPbyCTsLOzSYO4VPqS6aRqcz6ZQu0BAAAcAAAAHhWNBIAAAAAAAAAACAEAAAW"
-  "AAAAcAAAAAoAAADIAAAAAQAAAPAAAAAEAAAA/AAAAAUAAAAcAQAABwAAAEQBAACQAgAAJAIAAJgC"
-  "AACgAgAArAIAALwCAADIAgAAywIAAOMCAAD2AgAADQMAACEDAAA1AwAAUAMAAGwDAAB5AwAAhgMA"
-  "AJkDAACmAwAAqQMAAK0DAAC0AwAAvgMAAMYDAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAKAAAA"
-  "CwAAABAAAAARAAAAEAAAAAgAAAAAAAAABQAAABIAAAAFAAAAEwAAAAUAAAAUAAAABQAJABUAAAAC"
-  "AAAAAAAAAAQAAAAAAAAABQAAAAAAAAAGAAAAAAAAAAcAAAAAAAAABAAAAAEAAAD/////AAAAAA0A"
-  "AAAAAAAA5gMAAAAAAAABAAAAAQYAAAQAAAAAAAAADgAAAAAAAAAAAAAAAAAAAAIAAAABAAAABAAA"
-  "AAAAAAABAAAAAAAAAPADAAAAAAAAAwAAAAEGAAAEAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAFAAAA"
-  "AQAAAAQAAAAAAAAADwAAAAAAAAD6AwAAAAAAAAYAAAABAAAABAAAAAAAAAADAAAAAAAAAAwEAAAA"
-  "AAAABwAAAAEAAAAEAAAAAAAAAAwAAAAAAAAAFgQAAAAAAAABAAEAAAAAAM0DAAABAAAADgAAAAEA"
-  "AQABAAAA0gMAAAQAAABwEAEAAAAOAAEAAQABAAAA1wMAAAQAAABwEAEAAAAOAAEAAQABAAAA3AMA"
-  "AAQAAABwEAEAAAAOAAEAAQABAAAA4QMAAAQAAABwEAEAAAAOAAY8aW5pdD4ACkNsYXNzLmphdmEA"
-  "DkNsb25lYWJsZS5qYXZhAApGaWVsZC5qYXZhAAFJABZMamF2YS9pby9TZXJpYWxpemFibGU7ABFM"
-  "amF2YS9sYW5nL0NsYXNzOwAVTGphdmEvbGFuZy9DbG9uZWFibGU7ABJMamF2YS9sYW5nL09iamVj"
-  "dDsAEkxqYXZhL2xhbmcvU3RyaW5nOwAZTGphdmEvbGFuZy9yZWZsZWN0L0ZpZWxkOwAaTGphdmEv"
-  "bGFuZy9yZWZsZWN0L01ldGhvZDsAC01ldGhvZC5qYXZhAAtPYmplY3QuamF2YQARU2VyaWFsaXph"
-  "YmxlLmphdmEAC1N0cmluZy5qYXZhAAFWAAJbQwAFY291bnQACGhhc2hDb2RlAAZvZmZzZXQABXZh"
-  "bHVlAAMABw4ABQAHDgAFAAcOAAUABw4ABQAHDgAAAAEAAYGABKQEAAABAACBgAS4BAAEAQAAAAEA"
-  "AQABAAKBgATQBAAAAQADgYAE6AQAAAEABIGABIAFDAAAAAAAAAABAAAAAAAAAAEAAAAWAAAAcAAA"
-  "AAIAAAAKAAAAyAAAAAMAAAABAAAA8AAAAAQAAAAEAAAA/AAAAAUAAAAFAAAAHAEAAAYAAAAHAAAA"
-  "RAEAAAEgAAAFAAAAJAIAAAIgAAAWAAAAmAIAAAMgAAAFAAAAzQMAAAAgAAAFAAAA5gMAAAAQAAAB"
-  "AAAAIAQAAA==";
+  "ZGV4CjAzNQCf+7APoNCFqeL/QKrA9vK3fihkWcSko9nIBgAAcAAAAHhWNBIAAAAAAAAAADQGAAAg"
+  "AAAAcAAAAA0AAADwAAAAAQAAACQBAAAIAAAAMAEAAAgAAABwAQAACgAAALABAADYAwAA8AIAAKwD"
+  "AAC0AwAAzQMAANkDAADrAwAA+wMAAAcEAAAKBAAALgQAAE8EAABnBAAAegQAAJMEAACqBAAAvgQA"
+  "ANIEAADtBAAACQUAABYFAAAjBQAAOQUAAEwFAABZBQAAXAUAAGAFAABnBQAAcQUAAHkFAACHBQAA"
+  "kQUAAJkFAACjBQAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABAAAAAW"
+  "AAAAFwAAABYAAAALAAAAAAAAAAEACAAbAAAAAQAHAB4AAAAFAAcAHAAAAAUABQAdAAAACAAAABgA"
+  "AAAIAAAAGQAAAAgAAAAaAAAACAAMAB8AAAABAAAAAAAAAAIAAAAAAAAABAAAAAAAAAAFAAAAAAAA"
+  "AAcAAAAAAAAACAAAAAAAAAAJAAAAAAAAAAoAAAAAAAAABwAAAAEAAAD/////AAAAABIAAAAAAAAA"
+  "0gUAAAAAAAAFAAAAAQAAAAcAAAAAAAAAAwAAAAAAAADcBQAAAAAAAAEAAAABAAAABQAAAAAAAAAB"
+  "AAAAAAAAAOoFAAAAAAAAAgAAAAEAAAABAAAAAAAAABMAAAAAAAAA+AUAAAAAAAADAAAAAQYAAAcA"
+  "AAAAAAAAFAAAAAAAAAAAAAAAAAAAAAQAAAABAAAABwAAAAAAAAACAAAAAAAAAAIGAAAAAAAABgAA"
+  "AAEGAAAHAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAIAAAAAQAAAAcAAAAAAAAAFQAAAAAAAAAMBgAA"
+  "AAAAAAkAAAABAAAABwAAAAAAAAAFAAAAAAAAAB4GAAAAAAAACgAAAAEAAAAHAAAAAAAAABEAAAAA"
+  "AAAAKAYAAAAAAAABAAEAAAAAAKoFAAABAAAADgAAAAEAAQABAAAArwUAAAQAAABwEAQAAAAOAAEA"
+  "AQABAAAAtAUAAAQAAABwEAMAAAAOAAEAAQABAAAAuQUAAAQAAABwEAAAAAAOAAEAAQABAAAAvgUA"
+  "AAQAAABwEAQAAAAOAAEAAQABAAAAwwUAAAQAAABwEAQAAAAOAAEAAQABAAAAyAUAAAQAAABwEAQA"
+  "AAAOAAEAAQABAAAAzQUAAAQAAABwEAQAAAAOAAY8aW5pdD4AF0Jhc2VEZXhDbGFzc0xvYWRlci5q"
+  "YXZhAApDbGFzcy5qYXZhABBDbGFzc0xvYWRlci5qYXZhAA5DbG9uZWFibGUuamF2YQAKRmllbGQu"
+  "amF2YQABSQAiTGRhbHZpay9zeXN0ZW0vQmFzZURleENsYXNzTG9hZGVyOwAfTGRhbHZpay9zeXN0"
+  "ZW0vUGF0aENsYXNzTG9hZGVyOwAWTGphdmEvaW8vU2VyaWFsaXphYmxlOwARTGphdmEvbGFuZy9D"
+  "bGFzczsAF0xqYXZhL2xhbmcvQ2xhc3NMb2FkZXI7ABVMamF2YS9sYW5nL0Nsb25lYWJsZTsAEkxq"
+  "YXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7ABlMamF2YS9sYW5nL3JlZmxlY3Qv"
+  "RmllbGQ7ABpMamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kOwALTWV0aG9kLmphdmEAC09iamVjdC5q"
+  "YXZhABRQYXRoQ2xhc3NMb2FkZXIuamF2YQARU2VyaWFsaXphYmxlLmphdmEAC1N0cmluZy5qYXZh"
+  "AAFWAAJbQwAFY291bnQACGhhc2hDb2RlAAZvZmZzZXQADG9yaWdpbmFsUGF0aAAIcGFja2FnZXMA"
+  "BnBhcmVudAAIcGF0aExpc3QABXZhbHVlAAMABw4ABQAHDgAFAAcOAAUABw4ABQAHDgAFAAcOAAUA"
+  "Bw4ABQAHDgAAAAEABIGABPAFAAIBAAIAAQADgYAEhAYAAgEAAAABAACBgAScBgAAAQABgYAEtAYA"
+  "AAEAAoGABMwGAAQBAAQAAQABAAEABYGABOQGAAABAAaBgAT8BgAAAQAHgYAElAcAAAwAAAAAAAAA"
+  "AQAAAAAAAAABAAAAIAAAAHAAAAACAAAADQAAAPAAAAADAAAAAQAAACQBAAAEAAAACAAAADABAAAF"
+  "AAAACAAAAHABAAAGAAAACgAAALABAAABIAAACAAAAPACAAACIAAAIAAAAKwDAAADIAAACAAAAKoF"
+  "AAAAIAAACAAAANIFAAAAEAAAAQAAADQGAAA=";
 
 // package java.lang;
 // public class Object {}
@@ -288,6 +312,13 @@
     class_linker_ = runtime_->GetClassLinker();
   }
 
+  PathClassLoader* AllocPathClassLoader(const DexFile* dex_file) {
+    class_linker_->RegisterDexFile(dex_file);
+    std::vector<const DexFile*> dex_files;
+    dex_files.push_back(dex_file);
+    return class_linker_->AllocPathClassLoader(dex_files);
+  }
+
   bool is_host_;
   scoped_ptr_malloc<char> android_data_;
   std::string art_cache_;
diff --git a/src/dex_file.cc b/src/dex_file.cc
index 0cf98b1..35e98db 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -25,6 +25,18 @@
 const byte DexFile::kDexMagic[] = { 'd', 'e', 'x', '\n' };
 const byte DexFile::kDexMagicVersion[] = { '0', '3', '5', '\0' };
 
+DexFile::ClassPathEntry DexFile::FindInClassPath(const StringPiece& descriptor,
+                                                 ClassPath& class_path) {
+  for (size_t i = 0; i != class_path.size(); ++i) {
+    const DexFile* dex_file = class_path[i];
+    const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor);
+    if (dex_class_def != NULL) {
+      return ClassPathEntry(dex_file, dex_class_def);
+    }
+  }
+  return ClassPathEntry(NULL, NULL);
+}
+
 DexFile::Closer::~Closer() {}
 
 DexFile::MmapCloser::MmapCloser(void* addr, size_t length) : addr_(addr), length_(length) {
diff --git a/src/dex_file.h b/src/dex_file.h
index 6cc7b10..b4c6c47 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -4,6 +4,7 @@
 #define ART_SRC_DEX_FILE_H_
 
 #include <map>
+#include <vector>
 
 #include "globals.h"
 #include "leb128.h"
@@ -203,6 +204,13 @@
     uint32_t code_off_;
   };
 
+  typedef std::pair<const DexFile*, const DexFile::ClassDef*> ClassPathEntry;
+  typedef std::vector<const DexFile*> ClassPath;
+
+  // Search a collection of DexFiles for a descriptor
+  static ClassPathEntry FindInClassPath(const StringPiece& descriptor,
+                                        ClassPath& class_path);
+
   // Opens a .dex file from the file system.
   static DexFile* OpenFile(const std::string& filename);
 
diff --git a/src/heap.cc b/src/heap.cc
index bc54a82..86942fa 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -68,6 +68,9 @@
 }
 
 Object* Heap::AllocObject(Class* klass, size_t num_bytes) {
+  DCHECK((klass == NULL && num_bytes == sizeof(Class))
+         || klass->descriptor_ == NULL
+         || (klass->object_size_ == (klass->IsArray() ? 0 : num_bytes)));
   Object* obj = Allocate(num_bytes);
   if (obj != NULL) {
     obj->klass_ = klass;
diff --git a/src/jni_compiler_test.cc b/src/jni_compiler_test.cc
index 3041927..79806f6 100644
--- a/src/jni_compiler_test.cc
+++ b/src/jni_compiler_test.cc
@@ -204,9 +204,9 @@
 
 TEST_F(JniCompilerTest, CompileAndRunNoArgMethod) {
   scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
-  class_linker_->RegisterDexFile(dex.get());
+  PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
 
-  Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
+  Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
   ASSERT_TRUE(klass != NULL);
 
   Method* method = klass->FindVirtualMethod("foo", "()V");
@@ -233,9 +233,9 @@
 
 TEST_F(JniCompilerTest, CompileAndRunIntMethod) {
   scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
-  class_linker_->RegisterDexFile(dex.get());
+  PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
 
-  Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
+  Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
   ASSERT_TRUE(klass != NULL);
 
   Method* method = klass->FindVirtualMethod("fooI", "(I)I");
@@ -264,9 +264,9 @@
 
 TEST_F(JniCompilerTest, CompileAndRunIntIntMethod) {
   scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
-  class_linker_->RegisterDexFile(dex.get());
+  PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
 
-  Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
+  Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
   ASSERT_TRUE(klass != NULL);
 
   Method* method = klass->FindVirtualMethod("fooII", "(II)I");
@@ -298,9 +298,9 @@
 
 TEST_F(JniCompilerTest, CompileAndRunDoubleDoubleMethod) {
   scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
-  class_linker_->RegisterDexFile(dex.get());
+  PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
 
-  Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
+  Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
   ASSERT_TRUE(klass != NULL);
 
   Method* method = klass->FindVirtualMethod("fooDD", "(DD)D");
@@ -331,9 +331,9 @@
 
 TEST_F(JniCompilerTest, CompileAndRunIntObjectObjectMethod) {
   scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
-  class_linker_->RegisterDexFile(dex.get());
+  PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
 
-  Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
+  Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
   ASSERT_TRUE(klass != NULL);
 
   Method* method = klass->FindVirtualMethod(
@@ -392,9 +392,9 @@
 
 TEST_F(JniCompilerTest, CompileAndRunStaticIntObjectObjectMethod) {
   scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
-  class_linker_->RegisterDexFile(dex.get());
+  PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
 
-  Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
+  Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
   ASSERT_TRUE(klass != NULL);
 
   Method* method = klass->FindDirectMethod(
@@ -450,9 +450,9 @@
 
 TEST_F(JniCompilerTest, CompileAndRunStaticSynchronizedIntObjectObjectMethod) {
   scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
-  class_linker_->RegisterDexFile(dex.get());
+  PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
 
-  Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
+  Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
   ASSERT_TRUE(klass != NULL);
 
   Method* method = klass->FindDirectMethod(
@@ -514,9 +514,9 @@
 }
 TEST_F(JniCompilerTest, SuspendCountAcknolewdgement) {
   scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
-  class_linker_->RegisterDexFile(dex.get());
+  PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
 
-  Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
+  Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
   ASSERT_TRUE(klass != NULL);
 
   Method* method = klass->FindVirtualMethod("fooI", "(I)I");
@@ -559,9 +559,9 @@
 }
 TEST_F(JniCompilerTest, ExceptionHandling) {
   scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
-  class_linker_->RegisterDexFile(dex.get());
+  PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
 
-  Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
+  Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
   ASSERT_TRUE(klass != NULL);
 
   Method* method = klass->FindVirtualMethod("foo", "()V");
diff --git a/src/object.h b/src/object.h
index 3a9888e..d0f4a63 100644
--- a/src/object.h
+++ b/src/object.h
@@ -262,10 +262,11 @@
   }
 
   char GetType() const {  // TODO: return type
-    return descriptor_[0];
+    return GetDescriptor()[0];
   }
 
   const StringPiece& GetDescriptor() const {
+    DCHECK_NE(0, descriptor_.size());
     return descriptor_;
   }
 
@@ -648,13 +649,72 @@
   ObjectArray();
 };
 
+// ClassLoader objects.
+class ClassLoader : public Object {
+ public:
+  std::vector<const DexFile*>& GetClassPath() {
+    return class_path_;
+  }
+  void SetClassPath(std::vector<const DexFile*>& class_path) {
+    DCHECK_EQ(0U, class_path_.size());
+    class_path_ = class_path;
+  }
+
+ private:
+  // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
+  Object* packages_;
+  ClassLoader* parent_;
+
+  // TODO remove once we can create a real PathClassLoader
+  std::vector<const DexFile*> class_path_;
+
+  ClassLoader();
+};
+
+class BaseDexClassLoader : public ClassLoader {
+ private:
+  // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
+  String* original_path_;
+  Object* path_list_;
+  BaseDexClassLoader();
+};
+
+class PathClassLoader : public BaseDexClassLoader {
+ private:
+  PathClassLoader();
+};
+
 // Class objects.
 class Class : public Object {
  public:
+
+  // Class Status
+  //
+  // kStatusNotReady: If a Class cannot be found in the class table by
+  // FindClass, it allocates an new one with AllocClass in the
+  // kStatusNotReady and calls LoadClass. Note if it does find a
+  // class, it may not be kStatusResolved and it will try to push it
+  // forward toward kStatusResolved.
+  //
+  // kStatusIdx: LoadClass populates with Class with information from
+  // the DexFile, moving the status to kStatusIdx, indicating that the
+  // Class values in super_class_ and interfaces_ have not been
+  // populated based on super_class_idx_ and interfaces_idx_. The new
+  // Class can then be inserted into the classes table.
+  //
+  // kStatusLoaded: After taking a lock on Class, the ClassLinker will
+  // attempt to move a kStatusIdx class forward to kStatusLoaded by
+  // using ResolveClass to initialize the super_class_ and interfaces_.
+  //
+  // kStatusResolved: Still holding the lock on Class, the ClassLinker
+  // will use LinkClass to link all members, creating Field and Method
+  // objects, setting up the vtable, etc. On success, the class is
+  // marked kStatusResolved.
+
   enum Status {
     kStatusError = -1,
     kStatusNotReady = 0,
-    kStatusIdx = 1,  // loaded, DEX idx in super or ifaces
+    kStatusIdx = 1,  // loaded, DEX idx in super_class_idx_ and interfaces_idx_
     kStatusLoaded = 2,  // DEX idx values resolved
     kStatusResolved = 3,  // part of linking
     kStatusVerifying = 4,  // in the process of being verified
@@ -679,7 +739,7 @@
     return super_class_ != NULL;
   }
 
-  Object* GetClassLoader() const {
+  ClassLoader* GetClassLoader() const {
     return class_loader_;
   }
 
@@ -688,11 +748,11 @@
   }
 
   Class* GetComponentType() const {
-    DCHECK(IsArray());
     return component_type_;
   }
 
   const StringPiece& GetDescriptor() const {
+    DCHECK_NE(0, descriptor_.size());
     return descriptor_;
   }
 
@@ -732,7 +792,7 @@
 
   // Returns true if this class represents an array class.
   bool IsArray() const {
-    return descriptor_[0] == '[';  // TODO: avoid parsing the descriptor
+    return GetDescriptor()[0] == '[';  // TODO: avoid parsing the descriptor
   }
 
   // Returns true if the class is an interface.
@@ -933,7 +993,7 @@
   uint32_t super_class_idx_;
 
   // defining class loader, or NULL for the "bootstrap" system loader
-  Object* class_loader_;  // TODO: make an instance field
+  ClassLoader* class_loader_;  // TODO: make an instance field
 
   // initiating class loader list
   // NOTE: for classes with low serialNumber, these are unused, and the
@@ -1136,23 +1196,52 @@
   static uint16_t GetUtf16FromUtf8(const char** utf8_data_in) {
     uint8_t one = *(*utf8_data_in)++;
     if ((one & 0x80) == 0) {
-      /* one-byte encoding */
+      // one-byte encoding
       return one;
     }
-    /* two- or three-byte encoding */
+    // two- or three-byte encoding
     uint8_t two = *(*utf8_data_in)++;
     if ((one & 0x20) == 0) {
-      /* two-byte encoding */
+      // two-byte encoding
       return ((one & 0x1f) << 6) |
               (two & 0x3f);
     }
-    /* three-byte encoding */
+    // three-byte encoding
     uint8_t three = *(*utf8_data_in)++;
     return ((one & 0x0f) << 12) |
             ((two & 0x3f) << 6) |
             (three & 0x3f);
   }
 
+  // Like "strlen", but for strings encoded with "modified" UTF-8.
+  //
+  // The value returned is the number of characters, which may or may not
+  // be the same as the number of bytes.
+  //
+  // (If this needs optimizing, try: mask against 0xa0, shift right 5,
+  // get increment {1-3} from table of 8 values.)
+  static size_t ModifiedUtf8Len(const char* utf8) {
+    size_t len = 0;
+    int ic;
+    while ((ic = *utf8++) != '\0') {
+      len++;
+      if ((ic & 0x80) == 0) {
+        // one-byte encoding
+        continue;
+      }
+      // two- or three-byte encoding
+      utf8++;
+      if ((ic & 0x20) == 0) {
+        // two-byte encoding
+        continue;
+      }
+      // three-byte encoding
+      utf8++;
+    }
+    return len;
+  }
+
+
   // The java/lang/String.computeHashCode() algorithm
   static int32_t ComputeUtf16Hash(const uint16_t* string_data, size_t string_length) {
     int32_t hash = 0;