Merge "Verify thread state for all allocations, fix 2 failures" into dalvik-dev
diff --git a/src/class_linker.cc b/src/class_linker.cc
index cf0c094..87976a3 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -1178,7 +1178,7 @@
 
   } else {
     std::string class_name_string(DescriptorToDot(descriptor));
-    ScopedThreadStateChange(self, Thread::kNative);
+    ScopedThreadStateChange tsc(self, Thread::kNative);
     JNIEnv* env = self->GetJniEnv();
     ScopedLocalRef<jclass> c(env, AddLocalReference<jclass>(env, GetClassRoot(kJavaLangClassLoader)));
     CHECK(c.get() != NULL);
diff --git a/src/compiler.cc b/src/compiler.cc
index 4cc228c..ca9e53e 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -59,14 +59,10 @@
                    const std::set<std::string>* image_classes)
     : instruction_set_(instruction_set),
       jni_compiler_(instruction_set),
+      compiled_classes_lock_("compiled classes lock"),
+      compiled_methods_lock_("compiled method lock"),
+      compiled_invoke_stubs_lock_("compiled invoke stubs lock"),
       image_(image),
-      dex_file_count_(0),
-      class_count_(0),
-      abstract_method_count_(0),
-      native_method_count_(0),
-      regular_method_count_(0),
-      instruction_count_(0),
-      start_ns_(NanoTime()),
       image_classes_(image_classes) {
   CHECK(!Runtime::Current()->IsStarted());
   if (!image_) {
@@ -75,32 +71,17 @@
 }
 
 Compiler::~Compiler() {
-  STLDeleteValues(&compiled_classes_);
-  STLDeleteValues(&compiled_methods_);
-  STLDeleteValues(&compiled_invoke_stubs_);
-  if (dex_file_count_ > 0) {
-    uint64_t duration_ns = NanoTime() - start_ns_;
-    std::string stats(StringPrintf("Compiled files:%zd"
-                                   " classes:%zd"
-                                   " methods:(abstract:%zd"
-                                   " native:%zd"
-                                   " regular:%zd)"
-                                   " instructions:%zd",
-                                   dex_file_count_,
-                                   class_count_,
-                                   abstract_method_count_,
-                                   native_method_count_,
-                                   regular_method_count_,
-                                   instruction_count_));
-    stats += " (took ",
-    stats += PrettyDuration(duration_ns);
-    if (instruction_count_ != 0) {
-        stats += ", ";
-        stats += PrettyDuration(duration_ns / instruction_count_);
-        stats += "/instruction";
-    }
-    stats += ")";
-    LOG(INFO) << stats;
+  {
+    MutexLock mu(compiled_classes_lock_);
+    STLDeleteValues(&compiled_classes_);
+  }
+  {
+    MutexLock mu(compiled_methods_lock_);
+    STLDeleteValues(&compiled_methods_);
+  }
+  {
+    MutexLock mu(compiled_invoke_stubs_lock_);
+    STLDeleteValues(&compiled_invoke_stubs_);
   }
 }
 
@@ -251,6 +232,7 @@
 struct Context {
   ClassLinker* class_linker;
   const ClassLoader* class_loader;
+  Compiler* compiler;
   DexCache* dex_cache;
   const DexFile* dex_file;
 };
@@ -287,7 +269,6 @@
   }
 
   pthread_t pthread_;
-  Thread* thread_;
 
   Context* context_;
   size_t begin_;
@@ -296,24 +277,18 @@
   size_t stripe_;
 };
 
-class Workers {
- public:
-  Workers(Context* context, size_t begin, size_t end, Callback callback) {
-    const size_t thread_count = static_cast<size_t>(sysconf(_SC_NPROCESSORS_ONLN));
-    for (size_t i = 0; i < thread_count; ++i) {
-      threads_.push_back(new WorkerThread(context, begin + i, end, callback, thread_count));
-    }
+void ForAll(Context* context, size_t begin, size_t end, Callback callback) {
+  std::vector<WorkerThread*> threads;
+
+  const size_t thread_count = static_cast<size_t>(sysconf(_SC_NPROCESSORS_ONLN));
+  for (size_t i = 0; i < thread_count; ++i) {
+    threads.push_back(new WorkerThread(context, begin + i, end, callback, thread_count));
   }
 
-  ~Workers() {
-    // Switch to kVmWait while we're blocked waiting for the other threads to finish.
-    ScopedThreadStateChange tsc(Thread::Current(), Thread::kVmWait);
-    STLDeleteElements(&threads_);
-  }
-
- private:
-  std::vector<WorkerThread*> threads_;
-};
+  // Switch to kVmWait while we're blocked waiting for the other threads to finish.
+  ScopedThreadStateChange tsc(Thread::Current(), Thread::kVmWait);
+  STLDeleteElements(&threads);
+}
 
 static void ResolveClassFieldsAndMethods(Context* context, size_t class_def_index) {
   const DexFile& dex_file = *context->dex_file;
@@ -413,14 +388,10 @@
   context.dex_cache = dex_cache;
   context.dex_file = &dex_file;
 
-  {
-    Workers workers(&context, 0, dex_cache->NumResolvedTypes(), ResolveType);
-  }
+  ForAll(&context, 0, dex_cache->NumResolvedTypes(), ResolveType);
   timings.AddSplit("Resolve " + dex_file.GetLocation() + " Types");
 
-  {
-    Workers workers(&context, 0, dex_file.NumClassDefs(), ResolveClassFieldsAndMethods);
-  }
+  ForAll(&context, 0, dex_file.NumClassDefs(), ResolveClassFieldsAndMethods);
   timings.AddSplit("Resolve " + dex_file.GetLocation() + " MethodsAndFields");
 }
 
@@ -465,7 +436,7 @@
   context.class_linker = Runtime::Current()->GetClassLinker();
   context.class_loader = class_loader;
   context.dex_file = &dex_file;
-  Workers workers(&context, 0, dex_file.NumClassDefs(), VerifyClass);
+  ForAll(&context, 0, dex_file.NumClassDefs(), VerifyClass);
 
   dex_file.ChangePermissions(PROT_READ);
 }
@@ -490,6 +461,7 @@
       // record the final class status if necessary
       Class::Status status = klass->GetStatus();
       ClassReference ref(&dex_file, class_def_index);
+      MutexLock mu(compiled_classes_lock_);
       CompiledClass* compiled_class = GetCompiledClass(ref);
       if (compiled_class == NULL) {
         compiled_class = new CompiledClass(status);
@@ -522,20 +494,13 @@
   }
 }
 
-void Compiler::CompileDexFile(const ClassLoader* class_loader, const DexFile& dex_file) {
-  ++dex_file_count_;
-  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);
-    CompileClass(class_def, class_loader, dex_file);
-  }
-}
-
-void Compiler::CompileClass(const DexFile::ClassDef& class_def, const ClassLoader* class_loader,
-                            const DexFile& dex_file) {
+void Compiler::CompileClass(Context* context, size_t class_def_index) {
+  const ClassLoader* class_loader = context->class_loader;
+  const DexFile& dex_file = *context->dex_file;
+  const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
   if (SkipClass(class_loader, dex_file, class_def)) {
     return;
   }
-  ++class_count_;
   const byte* class_data = dex_file.GetClassData(class_def);
   if (class_data == NULL) {
     // empty class, probably a marker interface
@@ -551,33 +516,37 @@
   }
   // Compile direct methods
   while (it.HasNextDirectMethod()) {
-    CompileMethod(it.GetMethodCodeItem(), it.GetMemberAccessFlags(), it.GetMemberIndex(),
-                  class_loader, dex_file);
+    context->compiler->CompileMethod(it.GetMethodCodeItem(), it.GetMemberAccessFlags(),
+                                     it.GetMemberIndex(), class_loader, dex_file);
     it.Next();
   }
   // Compile virtual methods
   while (it.HasNextVirtualMethod()) {
-    CompileMethod(it.GetMethodCodeItem(), it.GetMemberAccessFlags(), it.GetMemberIndex(),
-                  class_loader, dex_file);
+    context->compiler->CompileMethod(it.GetMethodCodeItem(), it.GetMemberAccessFlags(),
+                                     it.GetMemberIndex(), class_loader, dex_file);
     it.Next();
   }
   DCHECK(!it.HasNext());
 }
 
+void Compiler::CompileDexFile(const ClassLoader* class_loader, const DexFile& dex_file) {
+  Context context;
+  context.class_loader = class_loader;
+  context.compiler = this;
+  context.dex_file = &dex_file;
+  ForAll(&context, 0, dex_file.NumClassDefs(), Compiler::CompileClass);
+}
+
 void Compiler::CompileMethod(const DexFile::CodeItem* code_item, uint32_t access_flags,
                              uint32_t method_idx, const ClassLoader* class_loader,
                              const DexFile& dex_file) {
   CompiledMethod* compiled_method = NULL;
   uint64_t start_ns = NanoTime();
   if ((access_flags & kAccNative) != 0) {
-    ++native_method_count_;
     compiled_method = jni_compiler_.Compile(access_flags, method_idx, class_loader, dex_file);
     CHECK(compiled_method != NULL);
   } else if ((access_flags & kAccAbstract) != 0) {
-    ++abstract_method_count_;
   } else {
-    ++regular_method_count_;
-    instruction_count_ += code_item->insns_size_in_code_units_;
     compiled_method = oatCompileMethod(*this, code_item, access_flags, method_idx, class_loader,
                                        dex_file, kThumb2);
     CHECK(compiled_method != NULL) << PrettyMethod(method_idx, dex_file);
@@ -591,6 +560,7 @@
   if (compiled_method != NULL) {
     MethodReference ref(&dex_file, method_idx);
     CHECK(GetCompiledMethod(ref) == NULL) << PrettyMethod(method_idx, dex_file);
+    MutexLock mu(compiled_methods_lock_);
     compiled_methods_[ref] = compiled_method;
     DCHECK(GetCompiledMethod(ref) != NULL) << PrettyMethod(method_idx, dex_file);
   }
@@ -621,6 +591,7 @@
 }
 
 const CompiledInvokeStub* Compiler::FindInvokeStub(bool is_static, const char* shorty) const {
+  MutexLock mu(compiled_invoke_stubs_lock_);
   const std::string key(MakeInvokeStubKey(is_static, shorty));
   InvokeStubTable::const_iterator it = compiled_invoke_stubs_.find(key);
   if (it == compiled_invoke_stubs_.end()) {
@@ -633,11 +604,13 @@
 
 void Compiler::InsertInvokeStub(bool is_static, const char* shorty,
                                 const CompiledInvokeStub* compiled_invoke_stub) {
+  MutexLock mu(compiled_invoke_stubs_lock_);
   std::string key(MakeInvokeStubKey(is_static, shorty));
   compiled_invoke_stubs_[key] = compiled_invoke_stub;
 }
 
 CompiledClass* Compiler::GetCompiledClass(ClassReference ref) const {
+  MutexLock mu(compiled_classes_lock_);
   ClassTable::const_iterator it = compiled_classes_.find(ref);
   if (it == compiled_classes_.end()) {
     return NULL;
@@ -647,6 +620,7 @@
 }
 
 CompiledMethod* Compiler::GetCompiledMethod(MethodReference ref) const {
+  MutexLock mu(compiled_methods_lock_);
   MethodTable::const_iterator it = compiled_methods_.find(ref);
   if (it == compiled_methods_.end()) {
     return NULL;
diff --git a/src/compiler.h b/src/compiler.h
index b43d5f6..f5f8cfa 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -33,6 +33,7 @@
 
 namespace art {
 
+class Context;
 class TimingLogger;
 
 class Compiler {
@@ -135,6 +136,8 @@
   void CompileMethod(const DexFile::CodeItem* code_item, uint32_t access_flags, uint32_t method_idx,
                      const ClassLoader* class_loader, const DexFile& dex_file);
 
+  static void CompileClass(Context* context, size_t class_def_index);
+
   void SetGcMaps(const ClassLoader* class_loader, const std::vector<const DexFile*>& dex_files);
   void SetGcMapsDexFile(const ClassLoader* class_loader, const DexFile& dex_file);
   void SetGcMapsMethod(const DexFile& dex_file, Method* method);
@@ -152,24 +155,21 @@
 
   typedef std::map<const ClassReference, CompiledClass*> ClassTable;
   // All class references that this compiler has compiled
+  mutable Mutex compiled_classes_lock_;
   ClassTable compiled_classes_;
 
   typedef std::map<const MethodReference, CompiledMethod*> MethodTable;
   // All method references that this compiler has compiled
+  mutable Mutex compiled_methods_lock_;
   MethodTable compiled_methods_;
 
   typedef std::map<std::string, const CompiledInvokeStub*> InvokeStubTable;
   // Invocation stubs created to allow invocation of the compiled methods
+  mutable Mutex compiled_invoke_stubs_lock_;
   InvokeStubTable compiled_invoke_stubs_;
 
   bool image_;
 
-  size_t dex_file_count_;
-  size_t class_count_;
-  size_t abstract_method_count_;
-  size_t native_method_count_;
-  size_t regular_method_count_;
-  size_t instruction_count_;
   uint64_t start_ns_;
 
   const std::set<std::string>* image_classes_;
diff --git a/src/dalvik_system_VMRuntime.cc b/src/dalvik_system_VMRuntime.cc
index 4ec2af8..b953248 100644
--- a/src/dalvik_system_VMRuntime.cc
+++ b/src/dalvik_system_VMRuntime.cc
@@ -134,9 +134,13 @@
 
 void VMRuntime_trimHeap(JNIEnv* env, jobject) {
   ScopedHeapLock heap_lock;
+  size_t alloc_space_size = Heap::GetAllocSpace()->Size();
+  float utilization = static_cast<float>(Heap::GetBytesAllocated()) / alloc_space_size;
   uint64_t start_ns = NanoTime();
   Heap::GetAllocSpace()->Trim();
-  VLOG(gc) << "VMRuntime_trimHeap took " << PrettyDuration(NanoTime() - start_ns);
+  LOG(INFO) << "Parallel heap trimming took " << PrettyDuration(NanoTime() - start_ns)
+            << " on a " << PrettySize(alloc_space_size)
+            << " heap with " << static_cast<int>(100 * utilization) << "% utilization";
 }
 
 JNINativeMethod gMethods[] = {
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index 7a6829e..c4ca894 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -110,7 +110,8 @@
 
   ~Dex2Oat() {
     delete runtime_;
-    LOG(INFO) << "dex2oat took " << PrettyDuration(NanoTime() - start_ns_);
+    const size_t thread_count = static_cast<size_t>(sysconf(_SC_NPROCESSORS_ONLN));
+    LOG(INFO) << "dex2oat took " << PrettyDuration(NanoTime() - start_ns_) << " (threads: " << thread_count << ")";
   }
 
   // Make a list of descriptors for classes to include in the image
diff --git a/src/thread_x86.cc b/src/thread_x86.cc
index 4f61e66..85da1f3 100644
--- a/src/thread_x86.cc
+++ b/src/thread_x86.cc
@@ -36,8 +36,8 @@
 #if defined(__APPLE__)
   UNIMPLEMENTED(WARNING);
 #else
-  // TODO: create specific lock for LDT modification
-  ScopedThreadListLock mutex;  // Avoid concurrent modification of the LDT
+  static Mutex modify_ldt_lock("modify_ldt lock");
+  MutexLock mu(modify_ldt_lock);
 
   // Read LDT
   CHECK_EQ((size_t)LDT_ENTRY_SIZE, sizeof(uint64_t));