Remove the barrier between each compilation of dex files.

Change-Id: I14392283cd59189f91f9aa947135a15c44ca5731
diff --git a/src/compiler.cc b/src/compiler.cc
index 155e8be..ce1803c 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -1235,13 +1235,157 @@
   }
 }
 
+// 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(Context *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_) {
+      CHECK_PTHREAD_CALL(pthread_create, (&pthread_, NULL, &Go, this), "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);
+    }
+    Thread::Current()->SetState(kRunnable);
+    worker->Run();
+    if (worker->spawn_) {
+      Thread::Current()->SetState(kNative);
+      runtime->DetachCurrentThread();
+    }
+    return NULL;
+  }
+
+  void Go() {
+    Go(this);
+  }
+
+  void SwitchToDexFile(size_t dex_file_index) {
+    CHECK (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 and
+    //       dex_cache in the context for the current working dex file.
+    context_ = new Context(/* class_linker */NULL,
+                           worker_context_->GetClassLoader(),
+                           worker_context_->GetCompiler(),
+                           /* dex_cache */NULL, 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);
+      CHECK(!self->IsExceptionPending()) << PrettyTypeOf(self->GetException());
+    }
+  }
+
+  pthread_t pthread_;
+  bool spawn_;
+
+  Context* worker_context_;
+  Callback* class_callback_;
+  const std::vector<const DexFile*>& dex_files_;
+
+  Context* context_;
+  volatile int32_t* shared_class_index_;
+
+  friend void ForClassesInAllDexFiles(Context*,
+                                      const std::vector<const DexFile*>&,
+                                      Callback, size_t);
+};
+
+void ForClassesInAllDexFiles(Context* worker_context,
+                             const std::vector<const DexFile*>& dex_files,
+                             Callback class_callback, size_t thread_count) {
+  Thread* self = Thread::Current();
+  CHECK(!self->IsExceptionPending()) << PrettyTypeOf(self->GetException());
+  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();
+
+  // Switch to kVmWait while we're blocked waiting for the other threads to finish.
+  ScopedThreadStateChange tsc(self, kVmWait);
+  STLDeleteElements(&threads);
+}
+
 void Compiler::Compile(const ClassLoader* class_loader,
                        const std::vector<const DexFile*>& dex_files) {
+#if defined(ART_USE_LLVM_COMPILER)
+  if (dex_files.size() <= 0) {
+    return;  // No dex file
+  }
+  Context context(NULL, class_loader, this, NULL, NULL);
+  ForClassesInAllDexFiles(&context, dex_files, Compiler::CompileClass, thread_count_);
+#else
   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);
   }
+#endif
 }
 
 void Compiler::CompileClass(Context* context, size_t class_def_index) {