ART: PathClassLoader for compiler

Use an actual PathClassLoader when compiling apps, instead of a
side structure and cutout.

This CL sets up a minimal object 'cluster' that recreates the Java
side of a regular ClassLoader such that the Class-Linker will
recognize it and use the internal native fast-path.

This CL removes the now unnecessary compile-time-classpath and
replaces it with a single 'compiling-the-boot-image' flag in the
compiler callbacks.

Note: This functionality is *only* intended for the compiler, as
the objects have not been completely initialized.

Bug: 19781184

Change-Id: I7f36af12dd7852d21281110a25c119e8c0669c1d
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 67872d7..b81a99a 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1372,38 +1372,6 @@
       self->SetException(pre_allocated);
       return nullptr;
     }
-  } else if (Runtime::Current()->UseCompileTimeClassPath()) {
-    // First try with the bootstrap class loader.
-    if (class_loader.Get() != nullptr) {
-      klass = LookupClass(self, descriptor, hash, nullptr);
-      if (klass != nullptr) {
-        return EnsureResolved(self, descriptor, klass);
-      }
-    }
-    // If the lookup failed search the boot class path. We don't perform a recursive call to avoid
-    // a NoClassDefFoundError being allocated.
-    ClassPathEntry pair = FindInClassPath(descriptor, hash, boot_class_path_);
-    if (pair.second != nullptr) {
-      return DefineClass(self, descriptor, hash, NullHandle<mirror::ClassLoader>(), *pair.first,
-                         *pair.second);
-    }
-    // Next try the compile time class path.
-    const std::vector<const DexFile*>* class_path;
-    {
-      ScopedObjectAccessUnchecked soa(self);
-      ScopedLocalRef<jobject> jclass_loader(soa.Env(),
-                                            soa.AddLocalReference<jobject>(class_loader.Get()));
-      class_path = &Runtime::Current()->GetCompileTimeClassPath(jclass_loader.get());
-    }
-    pair = FindInClassPath(descriptor, hash, *class_path);
-    if (pair.second != nullptr) {
-      return DefineClass(self, descriptor, hash, class_loader, *pair.first, *pair.second);
-    } else {
-      // Use the pre-allocated NCDFE at compile time to avoid wasting time constructing exceptions.
-      mirror::Throwable* pre_allocated = Runtime::Current()->GetPreAllocatedNoClassDefFoundError();
-      self->SetException(pre_allocated);
-      return nullptr;
-    }
   } else {
     ScopedObjectAccessUnchecked soa(self);
     mirror::Class* cp_klass = FindClassInPathClassLoader(soa, self, descriptor, hash,
@@ -1411,6 +1379,14 @@
     if (cp_klass != nullptr) {
       return cp_klass;
     }
+
+    if (Runtime::Current()->IsAotCompiler()) {
+      // Oops, compile-time, can't run actual class-loader code.
+      mirror::Throwable* pre_allocated = Runtime::Current()->GetPreAllocatedNoClassDefFoundError();
+      self->SetException(pre_allocated);
+      return nullptr;
+    }
+
     ScopedLocalRef<jobject> class_loader_object(soa.Env(),
                                                 soa.AddLocalReference<jobject>(class_loader.Get()));
     std::string class_name_string(DescriptorToDot(descriptor));
@@ -1767,7 +1743,7 @@
     return;  // No direct methods => no static methods.
   }
   Runtime* runtime = Runtime::Current();
-  if (!runtime->IsStarted() || runtime->UseCompileTimeClassPath()) {
+  if (!runtime->IsStarted()) {
     if (runtime->IsAotCompiler() || runtime->GetHeap()->HasImageSpace()) {
       return;  // OAT file unavailable.
     }
@@ -1907,7 +1883,7 @@
 
 
   bool has_oat_class = false;
-  if (Runtime::Current()->IsStarted() && !Runtime::Current()->UseCompileTimeClassPath()) {
+  if (Runtime::Current()->IsStarted() && !Runtime::Current()->IsAotCompiler()) {
     OatFile::OatClass oat_class = FindOatClass(dex_file, klass->GetDexClassDefIndex(),
                                                &has_oat_class);
     if (has_oat_class) {
@@ -2808,7 +2784,7 @@
   // classes.
   if (Runtime::Current()->IsAotCompiler()) {
     // Are we compiling the bootclasspath?
-    if (!Runtime::Current()->UseCompileTimeClassPath()) {
+    if (Runtime::Current()->GetCompilerCallbacks()->IsBootImage()) {
       return false;
     }
     // We are compiling an app (not the image).
@@ -5315,4 +5291,98 @@
   }
 }
 
+jobject ClassLinker::CreatePathClassLoader(Thread* self, std::vector<const DexFile*>& dex_files) {
+  // SOAAlreadyRunnable is protected, and we need something to add a global reference.
+  // We could move the jobject to the callers, but all call-sites do this...
+  ScopedObjectAccessUnchecked soa(self);
+
+  // Register the dex files.
+  for (const DexFile* dex_file : dex_files) {
+    RegisterDexFile(*dex_file);
+  }
+
+  // For now, create a libcore-level DexFile for each ART DexFile. This "explodes" multidex.
+  StackHandleScope<11> hs(self);
+
+  Handle<mirror::ArtField> h_dex_elements_field =
+      hs.NewHandle(soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList_dexElements));
+
+  mirror::Class* dex_elements_class = h_dex_elements_field->GetType(true);
+  DCHECK(dex_elements_class != nullptr);
+  DCHECK(dex_elements_class->IsArrayClass());
+  Handle<mirror::ObjectArray<mirror::Object>> h_dex_elements =
+      hs.NewHandle(reinterpret_cast<mirror::ObjectArray<mirror::Object>*>(
+          mirror::Array::Alloc<false>(self, dex_elements_class, dex_files.size(),
+                                      dex_elements_class->GetComponentSizeShift(),
+                                      Runtime::Current()->GetHeap()->GetCurrentAllocator())));
+  Handle<mirror::Class> h_dex_element_class =
+      hs.NewHandle(dex_elements_class->GetComponentType());
+
+  Handle<mirror::ArtField> h_element_file_field =
+      hs.NewHandle(
+          soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList__Element_dexFile));
+  DCHECK_EQ(h_dex_element_class.Get(), h_element_file_field->GetDeclaringClass());
+
+  Handle<mirror::ArtField> h_cookie_field =
+      hs.NewHandle(soa.DecodeField(WellKnownClasses::dalvik_system_DexFile_cookie));
+  DCHECK_EQ(h_cookie_field->GetDeclaringClass(), h_element_file_field->GetType(false));
+
+  // Fill the elements array.
+  int32_t index = 0;
+  for (const DexFile* dex_file : dex_files) {
+    StackHandleScope<3> hs2(self);
+
+    Handle<mirror::LongArray> h_long_array = hs2.NewHandle(mirror::LongArray::Alloc(self, 1));
+    DCHECK(h_long_array.Get() != nullptr);
+    h_long_array->Set(0, reinterpret_cast<intptr_t>(dex_file));
+
+    Handle<mirror::Object> h_dex_file = hs2.NewHandle(
+        h_cookie_field->GetDeclaringClass()->AllocObject(self));
+    DCHECK(h_dex_file.Get() != nullptr);
+    h_cookie_field->SetObject<false>(h_dex_file.Get(), h_long_array.Get());
+
+    Handle<mirror::Object> h_element = hs2.NewHandle(h_dex_element_class->AllocObject(self));
+    DCHECK(h_element.Get() != nullptr);
+    h_element_file_field->SetObject<false>(h_element.Get(), h_dex_file.Get());
+
+    h_dex_elements->Set(index, h_element.Get());
+    index++;
+  }
+  DCHECK_EQ(index, h_dex_elements->GetLength());
+
+  // Create DexPathList.
+  Handle<mirror::Object> h_dex_path_list = hs.NewHandle(
+      h_dex_elements_field->GetDeclaringClass()->AllocObject(self));
+  DCHECK(h_dex_path_list.Get() != nullptr);
+  // Set elements.
+  h_dex_elements_field->SetObject<false>(h_dex_path_list.Get(), h_dex_elements.Get());
+
+  // Create PathClassLoader.
+  Handle<mirror::Class> h_path_class_class = hs.NewHandle(
+      soa.Decode<mirror::Class*>(WellKnownClasses::dalvik_system_PathClassLoader));
+  Handle<mirror::Object> h_path_class_loader = hs.NewHandle(
+      h_path_class_class->AllocObject(self));
+  DCHECK(h_path_class_loader.Get() != nullptr);
+  // Set DexPathList.
+  Handle<mirror::ArtField> h_path_list_field = hs.NewHandle(
+      soa.DecodeField(WellKnownClasses::dalvik_system_PathClassLoader_pathList));
+  DCHECK(h_path_list_field.Get() != nullptr);
+  h_path_list_field->SetObject<false>(h_path_class_loader.Get(), h_dex_path_list.Get());
+
+  // Make a pretend boot-classpath.
+  // TODO: Should we scan the image?
+  Handle<mirror::ArtField> h_parent_field = hs.NewHandle(
+      mirror::Class::FindField(self, hs.NewHandle(h_path_class_loader->GetClass()), "parent",
+                               "Ljava/lang/ClassLoader;"));
+  DCHECK(h_parent_field.Get() != nullptr);
+  mirror::Object* boot_cl =
+      soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_BootClassLoader)->AllocObject(self);
+  h_parent_field->SetObject<false>(h_path_class_loader.Get(), boot_cl);
+
+  // Make it a global ref and return.
+  ScopedLocalRef<jobject> local_ref(
+      soa.Env(), soa.Env()->AddLocalReference<jobject>(h_path_class_loader.Get()));
+  return soa.Env()->NewGlobalRef(local_ref.get());
+}
+
 }  // namespace art
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 4ebce3e..88a2501 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -454,6 +454,11 @@
   bool MayBeCalledWithDirectCodePointer(mirror::ArtMethod* m)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  // Creates a GlobalRef PathClassLoader that can be used to load classes from the given dex files.
+  // Note: the objects are not completely set up. Do not use this outside of tests and the compiler.
+  jobject CreatePathClassLoader(Thread* self, std::vector<const DexFile*>& dex_files)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
  private:
   static void InitFromImageInterpretOnlyCallback(mirror::Object* obj, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 1789ab1..a895a49 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -621,6 +621,20 @@
   AssertNonExistentClass("LNoSuchClass;");
 }
 
+TEST_F(ClassLinkerTest, GetDexFiles) {
+  ScopedObjectAccess soa(Thread::Current());
+
+  jobject jclass_loader = LoadDex("Nested");
+  std::vector<const DexFile*> dex_files(GetDexFiles(jclass_loader));
+  ASSERT_EQ(dex_files.size(), 1U);
+  EXPECT_TRUE(EndsWith(dex_files[0]->GetLocation(), "Nested.jar"));
+
+  jobject jclass_loader2 = LoadDex("MultiDex");
+  std::vector<const DexFile*> dex_files2(GetDexFiles(jclass_loader2));
+  ASSERT_EQ(dex_files2.size(), 2U);
+  EXPECT_TRUE(EndsWith(dex_files2[0]->GetLocation(), "MultiDex.jar"));
+}
+
 TEST_F(ClassLinkerTest, FindClassNested) {
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<1> hs(soa.Self());
@@ -985,11 +999,10 @@
 
   ScopedObjectAccess soa(Thread::Current());
   jobject jclass_loader = LoadDex("StaticsFromCode");
+  const DexFile* dex_file = GetFirstDexFile(jclass_loader);
   StackHandleScope<1> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
       hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
-  const DexFile* dex_file = Runtime::Current()->GetCompileTimeClassPath(jclass_loader)[0];
-  CHECK(dex_file != nullptr);
   mirror::Class* klass = class_linker_->FindClass(soa.Self(), "LStaticsFromCode;", class_loader);
   mirror::ArtMethod* clinit = klass->FindClassInitializer();
   mirror::ArtMethod* getS0 = klass->FindDirectMethod("getS0", "()Ljava/lang/Object;");
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index e0d62d7..4104509 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -34,6 +34,7 @@
 #include "gc_root-inl.h"
 #include "gc/heap.h"
 #include "gtest/gtest.h"
+#include "handle_scope-inl.h"
 #include "interpreter/unstarted_runtime.h"
 #include "jni_internal.h"
 #include "mirror/class_loader.h"
@@ -386,22 +387,89 @@
   return std::move(vector[0]);
 }
 
+std::vector<const DexFile*> CommonRuntimeTest::GetDexFiles(jobject jclass_loader) {
+  std::vector<const DexFile*> ret;
+
+  ScopedObjectAccess soa(Thread::Current());
+
+  StackHandleScope<4> hs(Thread::Current());
+  Handle<mirror::ClassLoader> class_loader = hs.NewHandle(
+      soa.Decode<mirror::ClassLoader*>(jclass_loader));
+
+  DCHECK_EQ(class_loader->GetClass(),
+            soa.Decode<mirror::Class*>(WellKnownClasses::dalvik_system_PathClassLoader));
+  DCHECK_EQ(class_loader->GetParent()->GetClass(),
+            soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_BootClassLoader));
+
+  // The class loader is a PathClassLoader which inherits from BaseDexClassLoader.
+  // We need to get the DexPathList and loop through it.
+  Handle<mirror::ArtField> cookie_field =
+      hs.NewHandle(soa.DecodeField(WellKnownClasses::dalvik_system_DexFile_cookie));
+  Handle<mirror::ArtField> dex_file_field =
+      hs.NewHandle(
+          soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList__Element_dexFile));
+  mirror::Object* dex_path_list =
+      soa.DecodeField(WellKnownClasses::dalvik_system_PathClassLoader_pathList)->
+      GetObject(class_loader.Get());
+  if (dex_path_list != nullptr && dex_file_field.Get() != nullptr &&
+      cookie_field.Get() != nullptr) {
+    // DexPathList has an array dexElements of Elements[] which each contain a dex file.
+    mirror::Object* dex_elements_obj =
+        soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList_dexElements)->
+        GetObject(dex_path_list);
+    // Loop through each dalvik.system.DexPathList$Element's dalvik.system.DexFile and look
+    // at the mCookie which is a DexFile vector.
+    if (dex_elements_obj != nullptr) {
+      Handle<mirror::ObjectArray<mirror::Object>> dex_elements =
+          hs.NewHandle(dex_elements_obj->AsObjectArray<mirror::Object>());
+      for (int32_t i = 0; i < dex_elements->GetLength(); ++i) {
+        mirror::Object* element = dex_elements->GetWithoutChecks(i);
+        if (element == nullptr) {
+          // Should never happen, fall back to java code to throw a NPE.
+          break;
+        }
+        mirror::Object* dex_file = dex_file_field->GetObject(element);
+        if (dex_file != nullptr) {
+          mirror::LongArray* long_array = cookie_field->GetObject(dex_file)->AsLongArray();
+          DCHECK(long_array != nullptr);
+          int32_t long_array_size = long_array->GetLength();
+          for (int32_t j = 0; j < long_array_size; ++j) {
+            const DexFile* cp_dex_file = reinterpret_cast<const DexFile*>(static_cast<uintptr_t>(
+                long_array->GetWithoutChecks(j)));
+            if (cp_dex_file == nullptr) {
+              LOG(WARNING) << "Null DexFile";
+              continue;
+            }
+            ret.push_back(cp_dex_file);
+          }
+        }
+      }
+    }
+  }
+
+  return ret;
+}
+
+const DexFile* CommonRuntimeTest::GetFirstDexFile(jobject jclass_loader) {
+  std::vector<const DexFile*> tmp(GetDexFiles(jclass_loader));
+  DCHECK(!tmp.empty());
+  const DexFile* ret = tmp[0];
+  DCHECK(ret != nullptr);
+  return ret;
+}
+
 jobject CommonRuntimeTest::LoadDex(const char* dex_name) {
   std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles(dex_name);
   std::vector<const DexFile*> class_path;
   CHECK_NE(0U, dex_files.size());
   for (auto& dex_file : dex_files) {
     class_path.push_back(dex_file.get());
-    class_linker_->RegisterDexFile(*dex_file);
     loaded_dex_files_.push_back(std::move(dex_file));
   }
+
   Thread* self = Thread::Current();
-  JNIEnvExt* env = self->GetJniEnv();
-  ScopedLocalRef<jobject> class_loader_local(env,
-      env->AllocObject(WellKnownClasses::dalvik_system_PathClassLoader));
-  jobject class_loader = env->NewGlobalRef(class_loader_local.get());
-  self->SetClassLoaderOverride(class_loader_local.get());
-  Runtime::Current()->SetCompileTimeClassPath(class_loader, class_path);
+  jobject class_loader = Runtime::Current()->GetClassLinker()->CreatePathClassLoader(self,                                                                                   class_path);
+  self->SetClassLoaderOverride(class_loader);
   return class_loader;
 }
 
diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h
index cce8485..a29487f 100644
--- a/runtime/common_runtime_test.h
+++ b/runtime/common_runtime_test.h
@@ -133,6 +133,13 @@
   const DexFile* java_lang_dex_file_;
   std::vector<const DexFile*> boot_class_path_;
 
+  // Get the dex files from a PathClassLoader. This in order of the dex elements and their dex
+  // arrays.
+  std::vector<const DexFile*> GetDexFiles(jobject jclass_loader);
+
+  // Get the first dex file from a PathClassLoader. Will abort if it is null.
+  const DexFile* GetFirstDexFile(jobject jclass_loader);
+
  private:
   static std::string GetCoreFileLocation(const char* suffix);
 
diff --git a/runtime/compiler_callbacks.h b/runtime/compiler_callbacks.h
index d1a6861..3fabe3e 100644
--- a/runtime/compiler_callbacks.h
+++ b/runtime/compiler_callbacks.h
@@ -40,8 +40,16 @@
     // done so. Return false if relocating in this way would be problematic.
     virtual bool IsRelocationPossible() = 0;
 
+    bool IsBootImage() {
+      return boot_image_;
+    }
+
   protected:
-    CompilerCallbacks() { }
+    explicit CompilerCallbacks(bool boot_image) : boot_image_(boot_image) { }
+
+  private:
+    // Whether the compiler is creating a boot image.
+    const bool boot_image_;
 };
 
 }  // namespace art
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index 6063e1e..566b097 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -164,8 +164,10 @@
   // See if the override ClassLoader is set for gtests.
   class_loader = soa.Decode<mirror::ClassLoader*>(soa.Self()->GetClassLoaderOverride());
   if (class_loader != nullptr) {
-    // If so, CommonCompilerTest should have set UseCompileTimeClassPath.
-    CHECK(Runtime::Current()->UseCompileTimeClassPath());
+    // If so, CommonCompilerTest should have marked the runtime as a compiler not compiling an
+    // image.
+    CHECK(Runtime::Current()->IsAotCompiler());
+    CHECK(!Runtime::Current()->GetCompilerCallbacks()->IsBootImage());
     return class_loader;
   }
   // Use the BOOTCLASSPATH.
diff --git a/runtime/mirror/art_field.cc b/runtime/mirror/art_field.cc
index 3cea4a1..5d543a1 100644
--- a/runtime/mirror/art_field.cc
+++ b/runtime/mirror/art_field.cc
@@ -45,7 +45,7 @@
 void ArtField::SetOffset(MemberOffset num_bytes) {
   DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
   if (kIsDebugBuild && Runtime::Current()->IsAotCompiler() &&
-      !Runtime::Current()->UseCompileTimeClassPath()) {
+      Runtime::Current()->GetCompilerCallbacks()->IsBootImage()) {
     Primitive::Type type = GetTypeAsPrimitiveType();
     if (type == Primitive::kPrimDouble || type == Primitive::kPrimLong) {
       DCHECK_ALIGNED(num_bytes.Uint32Value(), 8);
diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc
index 21972a1..1ce298d 100644
--- a/runtime/mirror/object_test.cc
+++ b/runtime/mirror/object_test.cc
@@ -360,8 +360,7 @@
   // pretend we are trying to access 'Static.s0' from StaticsFromCode.<clinit>
   ScopedObjectAccess soa(Thread::Current());
   jobject class_loader = LoadDex("StaticsFromCode");
-  const DexFile* dex_file = Runtime::Current()->GetCompileTimeClassPath(class_loader)[0];
-  CHECK(dex_file != NULL);
+  const DexFile* dex_file = GetFirstDexFile(class_loader);
 
   StackHandleScope<2> hs(soa.Self());
   Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<ClassLoader*>(class_loader)));
diff --git a/runtime/noop_compiler_callbacks.h b/runtime/noop_compiler_callbacks.h
index 300abc9..a40659e 100644
--- a/runtime/noop_compiler_callbacks.h
+++ b/runtime/noop_compiler_callbacks.h
@@ -23,7 +23,7 @@
 
 class NoopCompilerCallbacks FINAL : public CompilerCallbacks {
  public:
-  NoopCompilerCallbacks() {}
+  NoopCompilerCallbacks() : CompilerCallbacks(false) {}
   ~NoopCompilerCallbacks() {}
 
   bool MethodVerified(verifier::MethodVerifier* verifier ATTRIBUTE_UNUSED) OVERRIDE {
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 9ca00b1..ffe3dc6 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -163,7 +163,6 @@
       method_trace_(false),
       method_trace_file_size_(0),
       instrumentation_(),
-      use_compile_time_class_path_(false),
       main_thread_group_(nullptr),
       system_thread_group_(nullptr),
       system_class_loader_(nullptr),
@@ -405,9 +404,9 @@
   return true;
 }
 
-static jobject CreateSystemClassLoader() {
-  if (Runtime::Current()->UseCompileTimeClassPath()) {
-    return NULL;
+static jobject CreateSystemClassLoader(Runtime* runtime) {
+  if (runtime->IsAotCompiler() && !runtime->GetCompilerCallbacks()->IsBootImage()) {
+    return nullptr;
   }
 
   ScopedObjectAccess soa(Thread::Current());
@@ -505,7 +504,7 @@
 
   Thread::FinishStartup();
 
-  system_class_loader_ = CreateSystemClassLoader();
+  system_class_loader_ = CreateSystemClassLoader(this);
 
   if (is_zygote_) {
     if (!InitZygote()) {
@@ -1483,23 +1482,6 @@
   callee_save_methods_[type] = GcRoot<mirror::ArtMethod>(method);
 }
 
-const std::vector<const DexFile*>& Runtime::GetCompileTimeClassPath(jobject class_loader) {
-  if (class_loader == NULL) {
-    return GetClassLinker()->GetBootClassPath();
-  }
-  CHECK(UseCompileTimeClassPath());
-  CompileTimeClassPaths::const_iterator it = compile_time_class_paths_.find(class_loader);
-  CHECK(it != compile_time_class_paths_.end());
-  return it->second;
-}
-
-void Runtime::SetCompileTimeClassPath(jobject class_loader,
-                                      std::vector<const DexFile*>& class_path) {
-  CHECK(!IsStarted());
-  use_compile_time_class_path_ = true;
-  compile_time_class_paths_.Put(class_loader, class_path);
-}
-
 void Runtime::StartProfiler(const char* profile_output_filename) {
   profile_output_filename_ = profile_output_filename;
   profiler_started_ =
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 9a04835..7181097 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -452,16 +452,6 @@
     return &instrumentation_;
   }
 
-  bool UseCompileTimeClassPath() const {
-    return use_compile_time_class_path_;
-  }
-
-  const std::vector<const DexFile*>& GetCompileTimeClassPath(jobject class_loader);
-
-  // The caller is responsible for ensuring the class_path DexFiles remain
-  // valid as long as the Runtime object remains valid.
-  void SetCompileTimeClassPath(jobject class_loader, std::vector<const DexFile*>& class_path);
-
   void StartProfiler(const char* profile_output_filename);
   void UpdateProfilerState(int state);
 
@@ -685,12 +675,6 @@
   size_t method_trace_file_size_;
   instrumentation::Instrumentation instrumentation_;
 
-  typedef AllocationTrackingSafeMap<jobject, std::vector<const DexFile*>,
-                                    kAllocatorTagCompileTimeClassPath, JobjectComparator>
-      CompileTimeClassPaths;
-  CompileTimeClassPaths compile_time_class_paths_;
-  bool use_compile_time_class_path_;
-
   jobject main_thread_group_;
   jobject system_thread_group_;