Make compiler initialization of classes parallel.

Fix hang where super class initialization could fail to notify threads
trying to initialize sub-class.
Unify logging to log file being compiled in all occurances.
Remove empty PostCompile method.
Remove experimental ForAllDexFile & Class code.

Change-Id: I471e9414f94d468d53b401e086f0fb65e36cc27c
diff --git a/src/compiler.cc b/src/compiler.cc
index e8bc390..771e3b4 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -483,11 +483,7 @@
 
   PreCompile(class_loader, dex_files, timings);
 
-  Compile(class_loader, dex_files);
-  timings.AddSplit("Compile");
-
-  PostCompile(class_loader, dex_files);
-  timings.AddSplit("PostCompile");
+  Compile(class_loader, dex_files, timings);
 
   if (dump_timings_ && timings.GetTotalNs() > MsToNs(1000)) {
     timings.Dump();
@@ -527,8 +523,6 @@
   CompileMethod(code_item, method->GetAccessFlags(), method->GetInvokeType(),
                 method_idx, class_loader, *dex_file);
 
-  PostCompile(class_loader, dex_files);
-
   self->GetJniEnv()->DeleteGlobalRef(class_loader);
 
   self->TransitionFromSuspendedToRunnable();
@@ -547,14 +541,9 @@
                           TimingLogger& timings) {
   Resolve(class_loader, dex_files, timings);
 
-  Verify(class_loader, dex_files);
-  timings.AddSplit("PreCompile.Verify");
+  Verify(class_loader, dex_files, timings);
 
-  InitializeClassesWithoutClinit(class_loader, dex_files);
-  timings.AddSplit("PreCompile.InitializeClassesWithoutClinit");
-}
-
-void Compiler::PostCompile(jobject, const std::vector<const DexFile*>&) {
+  InitializeClassesWithoutClinit(class_loader, dex_files, timings);
 }
 
 bool Compiler::IsImageClass(const std::string& descriptor) const {
@@ -564,6 +553,11 @@
   return image_classes_->find(descriptor) != image_classes_->end();
 }
 
+void Compiler::RecordClassStatus(ClassReference ref, CompiledClass* compiled_class) {
+  MutexLock mu(Compiler::compiled_classes_lock_);
+  compiled_classes_.Put(ref, compiled_class);
+}
+
 bool Compiler::CanAssumeTypeIsPresentInDexCache(const DexFile& dex_file,
                                                 uint32_t type_idx) {
   ScopedObjectAccess soa(Thread::Current());
@@ -1207,11 +1201,12 @@
   timings.AddSplit("Resolve " + dex_file.GetLocation() + " MethodsAndFields");
 }
 
-void Compiler::Verify(jobject class_loader, const std::vector<const DexFile*>& dex_files) {
+void Compiler::Verify(jobject class_loader, const std::vector<const DexFile*>& dex_files,
+                      TimingLogger& timings) {
   for (size_t i = 0; i != dex_files.size(); ++i) {
     const DexFile* dex_file = dex_files[i];
     CHECK(dex_file != NULL);
-    VerifyDexFile(class_loader, *dex_file);
+    VerifyDexFile(class_loader, *dex_file, timings);
   }
 }
 
@@ -1261,235 +1256,73 @@
   CHECK(!Thread::Current()->IsExceptionPending()) << PrettyTypeOf(Thread::Current()->GetException());
 }
 
-void Compiler::VerifyDexFile(jobject class_loader, const DexFile& dex_file) {
-  dex_file.ChangePermissions(PROT_READ | PROT_WRITE);
-
+void Compiler::VerifyDexFile(jobject class_loader, const DexFile& dex_file, TimingLogger& timings) {
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  jobject dex_cache;
-  {
-    ScopedObjectAccess soa(Thread::Current());
-    ScopedLocalRef<jobject>
-        dex_cache_local(soa.Env(),
-                        soa.AddLocalReference<jobject>(class_linker->FindDexCache(dex_file)));
-    dex_cache = soa.Env()->NewGlobalRef(dex_cache_local.get());
-  }
   CompilationContext context(class_linker, class_loader, this, &dex_file);
   ForAll(&context, 0, dex_file.NumClassDefs(), VerifyClass, thread_count_);
+  timings.AddSplit("Verify " + dex_file.GetLocation());
+}
 
-  Thread::Current()->GetJniEnv()->DeleteGlobalRef(dex_cache);
-  dex_file.ChangePermissions(PROT_READ);
+static void InitializeClassWithoutClinit(const CompilationContext* context,
+                                         size_t class_def_index)
+    LOCKS_EXCLUDED(Locks::mutator_lock_) {
+  const DexFile::ClassDef& class_def = context->GetDexFile()->GetClassDef(class_def_index);
+  ScopedObjectAccess soa(Thread::Current());
+  ClassLoader* class_loader = soa.Decode<ClassLoader*>(context->GetClassLoader());
+  const char* descriptor = context->GetDexFile()->GetClassDescriptor(class_def);
+  Class* klass = context->GetClassLinker()->FindClass(descriptor, class_loader);
+  if (klass != NULL) {
+    if (klass->IsVerified()) {
+      // Only try to initialize classes that were successfully verified.
+      bool compiling_boot = Runtime::Current()->GetHeap()->GetSpaces().size() == 1;
+      bool can_init_static_fields = compiling_boot &&
+          context->GetCompiler()->IsImageClass(descriptor);
+      context->GetClassLinker()->EnsureInitialized(klass, false, can_init_static_fields);
+      // If successfully initialized place in SSB array.
+      if (klass->IsInitialized()) {
+        klass->GetDexCache()->GetInitializedStaticStorage()->Set(klass->GetDexTypeIndex(), klass);
+      }
+    }
+    // Record the final class status if necessary.
+    Class::Status status = klass->GetStatus();
+    Compiler::ClassReference ref(context->GetDexFile(), class_def_index);
+    CompiledClass* compiled_class = context->GetCompiler()->GetCompiledClass(ref);
+    if (compiled_class == NULL) {
+      compiled_class = new CompiledClass(status);
+      context->GetCompiler()->RecordClassStatus(ref, compiled_class);
+    } else {
+      DCHECK_EQ(status, compiled_class->GetStatus());
+    }
+  }
+  // clear any class not found or verification exceptions
+  Thread::Current()->ClearException();
+}
+
+void Compiler::InitializeClassesWithoutClinit(jobject jni_class_loader, const DexFile& dex_file,
+                                              TimingLogger& timings) {
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  CompilationContext context(class_linker, jni_class_loader, this, &dex_file);
+  ForAll(&context, 0, dex_file.NumClassDefs(), InitializeClassWithoutClinit, thread_count_);
+  timings.AddSplit("InitializeNoClinit " + dex_file.GetLocation());
 }
 
 void Compiler::InitializeClassesWithoutClinit(jobject class_loader,
-                                              const std::vector<const DexFile*>& dex_files) {
+                                              const std::vector<const DexFile*>& dex_files,
+                                              TimingLogger& timings) {
   for (size_t i = 0; i != dex_files.size(); ++i) {
     const DexFile* dex_file = dex_files[i];
     CHECK(dex_file != NULL);
-    InitializeClassesWithoutClinit(class_loader, *dex_file);
+    InitializeClassesWithoutClinit(class_loader, *dex_file, timings);
   }
 }
 
-void Compiler::InitializeClassesWithoutClinit(jobject jni_class_loader, const DexFile& dex_file) {
-  ScopedObjectAccess soa(Thread::Current());
-  ClassLoader* class_loader = soa.Decode<ClassLoader*>(jni_class_loader);
-  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  for (size_t class_def_index = 0; class_def_index < dex_file.NumClassDefs(); class_def_index++) {
-    const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
-    const char* descriptor = dex_file.GetClassDescriptor(class_def);
-    Class* klass = class_linker->FindClass(descriptor, class_loader);
-    if (klass != NULL) {
-      if (klass->IsVerified()) {
-        // Only try to initialize classes that were successfully verified.
-        bool compiling_boot = Runtime::Current()->GetHeap()->GetSpaces().size() == 1;
-        bool can_init_static_fields = compiling_boot &&
-            IsImageClass(descriptor);
-        class_linker->EnsureInitialized(klass, false, can_init_static_fields);
-      }
-      // record the final class status if necessary
-      Class::Status status = klass->GetStatus();
-      ClassReference ref(&dex_file, class_def_index);
-      CompiledClass* compiled_class = GetCompiledClass(ref);
-      if (compiled_class == NULL) {
-        MutexLock mu(compiled_classes_lock_);
-        compiled_class = new CompiledClass(status);
-        compiled_classes_.Put(ref, compiled_class);
-      } else {
-        DCHECK_EQ(status, compiled_class->GetStatus());
-      }
-    }
-    // clear any class not found or verification exceptions
-    Thread::Current()->ClearException();
-  }
-
-  DexCache* dex_cache = class_linker->FindDexCache(dex_file);
-  for (size_t type_idx = 0; type_idx < dex_cache->NumResolvedTypes(); type_idx++) {
-    Class* klass = class_linker->ResolveType(dex_file, type_idx, dex_cache, class_loader);
-    if (klass == NULL) {
-      Thread::Current()->ClearException();
-    } else if (klass->IsInitialized()) {
-      dex_cache->GetInitializedStaticStorage()->Set(type_idx, klass);
-    }
-  }
-}
-
-// TODO: This class shares some implementation with WorkerThread. We don't want
-// to perturb the non-LLVM side at the same time. Staging the refactoring for
-// the future.
-class DexFilesWorkerThread {
- public:
-  DexFilesWorkerThread(CompilationContext *worker_context, Callback class_callback,
-                       const std::vector<const DexFile*>& dex_files,
-                       volatile int32_t* shared_class_index, bool spawn)
-      : spawn_(spawn), worker_context_(worker_context),
-        class_callback_(class_callback), dex_files_(dex_files),
-        context_(NULL), shared_class_index_(shared_class_index) {
-    if (spawn_) {
-      pthread_attr_t attr;
-      CHECK_PTHREAD_CALL(pthread_attr_init, (&attr), "new compiler worker thread");
-      CHECK_PTHREAD_CALL(pthread_attr_setstacksize, (&attr, 1*MB), "new compiler worker thread");
-      CHECK_PTHREAD_CALL(pthread_create, (&pthread_, &attr, &Go, this), "new compiler worker thread");
-      CHECK_PTHREAD_CALL(pthread_attr_destroy, (&attr), "new compiler worker thread");
-    }
-  }
-
-  ~DexFilesWorkerThread() {
-    if (spawn_) {
-      CHECK_PTHREAD_CALL(pthread_join, (pthread_, NULL), "compiler worker shutdown");
-    }
-    delete context_;
-  }
-
- private:
-  static void* Go(void* arg) {
-    DexFilesWorkerThread* worker = reinterpret_cast<DexFilesWorkerThread*>(arg);
-    Runtime* runtime = Runtime::Current();
-    if (worker->spawn_) {
-      runtime->AttachCurrentThread("Compiler Worker", true, NULL);
-    }
-    {
-      ScopedObjectAccess soa(Thread::Current());
-      worker->Run();
-    }
-    if (worker->spawn_) {
-      runtime->DetachCurrentThread();
-    }
-    return NULL;
-  }
-
-  void Go() {
-    Go(this);
-  }
-
-  void SwitchToDexFile(size_t dex_file_index) {
-    CHECK_LT(dex_file_index, dex_files_.size());
-
-    const DexFile* dex_file = dex_files_[dex_file_index];
-    CHECK(dex_file != NULL);
-
-    // Destroy the old context
-    delete context_;
-
-    // TODO: Add a callback to let the client specify the class_linker in the context for the
-    //       current working dex file.
-    context_ = new CompilationContext(/* class_linker */NULL,
-                                      worker_context_->GetClassLoader(),
-                                      worker_context_->GetCompiler(),
-                                      dex_file);
-
-    CHECK(context_ != NULL);
-  }
-
-  void Run() {
-    Thread* self = Thread::Current();
-    size_t cur_dex_file_index = 0;
-    size_t class_index_base = 0;
-
-    SwitchToDexFile(0);
-
-    while (true) {
-      size_t class_index = static_cast<size_t>(android_atomic_inc(shared_class_index_));
-
-      const DexFile* dex_file;
-      do {
-        dex_file = dex_files_[cur_dex_file_index];
-
-        if (class_index < (class_index_base + dex_file->NumClassDefs())) {
-          break;
-        }
-        class_index_base += dex_file->NumClassDefs();
-
-        cur_dex_file_index++;
-      } while (cur_dex_file_index < dex_files_.size());
-
-      if (cur_dex_file_index >= dex_files_.size()) {
-        return;
-      }
-
-      if (dex_file != context_->GetDexFile()) {
-        SwitchToDexFile(cur_dex_file_index);
-      }
-
-      class_index -= class_index_base;
-      class_callback_(context_, class_index);
-      self->AssertNoPendingException();
-    }
-  }
-
-  pthread_t pthread_;
-  bool spawn_;
-
-  CompilationContext* worker_context_;
-  Callback* class_callback_;
-  const std::vector<const DexFile*>& dex_files_;
-
-  CompilationContext* context_;
-  volatile int32_t* shared_class_index_;
-
-  friend void ForClassesInAllDexFiles(CompilationContext*,
-                                      const std::vector<const DexFile*>&,
-                                      Callback, size_t);
-};
-
-void ForClassesInAllDexFiles(CompilationContext* worker_context,
-                             const std::vector<const DexFile*>& dex_files,
-                             Callback class_callback, size_t thread_count) {
-  Thread* self = Thread::Current();
-  self->AssertNoPendingException();
-  CHECK_GT(thread_count, 0U);
-
-  std::vector<DexFilesWorkerThread*> threads;
-  volatile int32_t shared_class_index = 0;
-
-  for (size_t i = 0; i < thread_count; ++i) {
-    threads.push_back(new DexFilesWorkerThread(worker_context, class_callback,
-                                               dex_files, &shared_class_index,
-                                               /* spawn */ (i != 0)));
-  }
-  threads[0]->Go();
-
-  // Ensure we're suspended while we're blocked waiting for the other threads to finish (worker
-  // thread destructor's called below perform join).
-  {
-    MutexLock mu(*Locks::thread_suspend_count_lock_);
-    CHECK_NE(self->GetState(), kRunnable);
-  }
-  STLDeleteElements(&threads);
-}
-
-void Compiler::Compile(jobject class_loader, const std::vector<const DexFile*>& dex_files) {
-#if defined(ART_USE_LLVM_COMPILER)
-  if (dex_files.size() <= 0) {
-    return;  // No dex file
-  }
-  CompilationContext context(NULL, class_loader, this, NULL);
-  ForClassesInAllDexFiles(&context, dex_files, Compiler::CompileClass, thread_count_);
-#else
+void Compiler::Compile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
+                       TimingLogger& timings) {
   for (size_t i = 0; i != dex_files.size(); ++i) {
     const DexFile* dex_file = dex_files[i];
     CHECK(dex_file != NULL);
-    CompileDexFile(class_loader, *dex_file);
+    CompileDexFile(class_loader, *dex_file, timings);
   }
-#endif
 }
 
 void Compiler::CompileClass(const CompilationContext* context, size_t class_def_index) {
@@ -1556,9 +1389,11 @@
   DCHECK(!it.HasNext());
 }
 
-void Compiler::CompileDexFile(jobject class_loader, const DexFile& dex_file) {
+void Compiler::CompileDexFile(jobject class_loader, const DexFile& dex_file,
+                              TimingLogger& timings) {
   CompilationContext context(NULL, class_loader, this, &dex_file);
   ForAll(&context, 0, dex_file.NumClassDefs(), Compiler::CompileClass, thread_count_);
+  timings.AddSplit("Compile " + dex_file.GetLocation());
 }
 
 static std::string MakeInvokeStubKey(bool is_static, const char* shorty) {