Fix the compiler to resolve against the boot class loader first.

I encountered a bug due to vogar including its own ancient copy
of Kxml. We were using vogar's Kxml at compile time and the boot
class path's Kxml at runtime, resulting in incorrect behavior.

This fixes the class linker to use the same parent-first strategy
in the compiler as in the runtime.

The result is that compiling vogar with the ancient Kxml will now
crash the compiler (fail fast) rather than doing undefined bad
things at runtime.

I've opened bug http://b/5663506 to fix the compiler to throw
linkage errors at runtime rather than crashing.

Change-Id: I60702e8687f1b763b58895e7f75c6abeb32a11a0
diff --git a/src/class_linker.cc b/src/class_linker.cc
index c214b5f..4598ae9 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -979,42 +979,50 @@
   // Class is not yet loaded.
   if (descriptor[0] == '[') {
     return CreateArrayClass(descriptor, class_loader);
-  }
-  if (class_loader == NULL) {
-    DexFile::ClassPathEntry pair = DexFile::FindInClassPath(descriptor, boot_class_path_);
-    if (pair.second == NULL) {
-      std::string name(PrintableString(descriptor));
-      ThrowNoClassDefFoundError("Class %s not found in boot class loader", name.c_str());
-      return NULL;
-    }
-    return DefineClass(descriptor, NULL, *pair.first, *pair.second);
-  }
 
-  if (ClassLoader::UseCompileTimeClassPath()) {
+  } else if (class_loader == NULL) {
+    DexFile::ClassPathEntry pair = DexFile::FindInClassPath(descriptor, boot_class_path_);
+    if (pair.second != NULL) {
+      return DefineClass(descriptor, NULL, *pair.first, *pair.second);
+    }
+
+  } else if (ClassLoader::UseCompileTimeClassPath()) {
+    // first try the boot class path
+    Class* system_class = FindSystemClass(descriptor);
+    if (system_class != NULL) {
+      return system_class;
+    }
+    CHECK(self->IsExceptionPending());
+    self->ClearException();
+
+    // next try the compile time class path
     const std::vector<const DexFile*>& class_path
         = ClassLoader::GetCompileTimeClassPath(class_loader);
     DexFile::ClassPathEntry pair = DexFile::FindInClassPath(descriptor, class_path);
-    if (pair.second == NULL) {
-      return FindSystemClass(descriptor);
+    if (pair.second != NULL) {
+      return DefineClass(descriptor, class_loader, *pair.first, *pair.second);
     }
-    return DefineClass(descriptor, class_loader, *pair.first, *pair.second);
+
+  } else {
+    std::string class_name_string = DescriptorToDot(descriptor);
+    ScopedThreadStateChange(self, Thread::kNative);
+    JNIEnv* env = self->GetJniEnv();
+    ScopedLocalRef<jclass> c(env, AddLocalReference<jclass>(env, GetClassRoot(kJavaLangClassLoader)));
+    CHECK(c.get() != NULL);
+    // TODO: cache method?
+    jmethodID mid = env->GetMethodID(c.get(), "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
+    CHECK(mid != NULL);
+    ScopedLocalRef<jobject> class_name_object(env, env->NewStringUTF(class_name_string.c_str()));
+    if (class_name_object.get() == NULL) {
+      return NULL;
+    }
+    ScopedLocalRef<jobject> class_loader_object(env, AddLocalReference<jobject>(env, class_loader));
+    ScopedLocalRef<jobject> result(env, env->CallObjectMethod(class_loader_object.get(), mid, class_name_object.get()));
+    return Decode<Class*>(env, result.get());
   }
 
-  std::string class_name_string = DescriptorToDot(descriptor);
-  ScopedThreadStateChange(self, Thread::kNative);
-  JNIEnv* env = self->GetJniEnv();
-  ScopedLocalRef<jclass> c(env, AddLocalReference<jclass>(env, GetClassRoot(kJavaLangClassLoader)));
-  CHECK(c.get() != NULL);
-  // TODO: cache method?
-  jmethodID mid = env->GetMethodID(c.get(), "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
-  CHECK(mid != NULL);
-  ScopedLocalRef<jobject> class_name_object(env, env->NewStringUTF(class_name_string.c_str()));
-  if (class_name_object.get() == NULL) {
-    return NULL;
-  }
-  ScopedLocalRef<jobject> class_loader_object(env, AddLocalReference<jobject>(env, class_loader));
-  ScopedLocalRef<jobject> result(env, env->CallObjectMethod(class_loader_object.get(), mid, class_name_object.get()));
-  return Decode<Class*>(env, result.get());
+  ThrowNoClassDefFoundError("Class %s not found", PrintableString(descriptor).c_str());
+  return NULL;
 }
 
 Class* ClassLinker::DefineClass(const std::string& descriptor,
@@ -2707,7 +2715,8 @@
   if (resolved != NULL) {
     dex_cache->SetResolvedField(field_idx, resolved);
   } else {
-    DCHECK(Thread::Current()->IsExceptionPending())
+    // TODO: this check fails when the app class path contains a class from the boot class path
+    CHECK(Thread::Current()->IsExceptionPending())
         << PrettyClass(klass) << " " << name << " " << type << " " << is_static;
   }
   return resolved;