Re-enable parallel verification.

Check that when verifying and initializing a class the lock on the class
is held.
Add logging for slow verification of a method.

Change-Id: Id51f8a108b8d1801d61ee276fab5001ddc5c0044
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 2ee8bd8..a88a2d6 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -274,14 +274,14 @@
   SetClassRoot(kJavaLangString, java_lang_String.get());
 
   // Setup the primitive type classes.
-  SetClassRoot(kPrimitiveBoolean, CreatePrimitiveClass("Z", Primitive::kPrimBoolean));
-  SetClassRoot(kPrimitiveByte, CreatePrimitiveClass("B", Primitive::kPrimByte));
-  SetClassRoot(kPrimitiveShort, CreatePrimitiveClass("S", Primitive::kPrimShort));
-  SetClassRoot(kPrimitiveInt, CreatePrimitiveClass("I", Primitive::kPrimInt));
-  SetClassRoot(kPrimitiveLong, CreatePrimitiveClass("J", Primitive::kPrimLong));
-  SetClassRoot(kPrimitiveFloat, CreatePrimitiveClass("F", Primitive::kPrimFloat));
-  SetClassRoot(kPrimitiveDouble, CreatePrimitiveClass("D", Primitive::kPrimDouble));
-  SetClassRoot(kPrimitiveVoid, CreatePrimitiveClass("V", Primitive::kPrimVoid));
+  SetClassRoot(kPrimitiveBoolean, CreatePrimitiveClass(Primitive::kPrimBoolean));
+  SetClassRoot(kPrimitiveByte, CreatePrimitiveClass(Primitive::kPrimByte));
+  SetClassRoot(kPrimitiveShort, CreatePrimitiveClass(Primitive::kPrimShort));
+  SetClassRoot(kPrimitiveInt, CreatePrimitiveClass(Primitive::kPrimInt));
+  SetClassRoot(kPrimitiveLong, CreatePrimitiveClass(Primitive::kPrimLong));
+  SetClassRoot(kPrimitiveFloat, CreatePrimitiveClass(Primitive::kPrimFloat));
+  SetClassRoot(kPrimitiveDouble, CreatePrimitiveClass(Primitive::kPrimDouble));
+  SetClassRoot(kPrimitiveVoid, CreatePrimitiveClass(Primitive::kPrimVoid));
 
   // Create array interface entries to populate once we can load system classes
   array_iftable_ = AllocObjectArray<InterfaceEntry>(2);
@@ -327,7 +327,7 @@
   // now we can use FindSystemClass
 
   // run char class through InitializePrimitiveClass to finish init
-  InitializePrimitiveClass(char_class.get(), "C", Primitive::kPrimChar);
+  InitializePrimitiveClass(char_class.get(), Primitive::kPrimChar);
   SetClassRoot(kPrimitiveChar, char_class.get());  // needs descriptor
 
   // Object and String need to be rerun through FindSystemClass to finish init
@@ -1714,16 +1714,14 @@
   }
 }
 
-Class* ClassLinker::InitializePrimitiveClass(Class* primitive_class,
-                                             const char* descriptor,
-                                             Primitive::Type type) {
-  // TODO: deduce one argument from the other
+Class* ClassLinker::InitializePrimitiveClass(Class* primitive_class, Primitive::Type type) {
   CHECK(primitive_class != NULL);
+  ObjectLock lock(primitive_class);  // Must hold lock on object when initializing.
   primitive_class->SetAccessFlags(kAccPublic | kAccFinal | kAccAbstract);
   primitive_class->SetPrimitiveType(type);
   primitive_class->SetStatus(Class::kStatusInitialized);
-  Class* existing = InsertClass(descriptor, primitive_class, false);
-  CHECK(existing == NULL) << "InitPrimitiveClass(" << descriptor << ") failed";
+  Class* existing = InsertClass(Primitive::Descriptor(type), primitive_class, false);
+  CHECK(existing == NULL) << "InitPrimitiveClass(" << type << ") failed";
   return primitive_class;
 }
 
@@ -1803,6 +1801,7 @@
     }
     new_class->SetComponentType(component_type);
   }
+  ObjectLock lock(new_class.get());  // Must hold lock on object when initializing.
   DCHECK(new_class->GetComponentType() != NULL);
   Class* java_lang_Object = GetClassRoot(kJavaLangObject);
   new_class->SetSuperClass(java_lang_Object);
@@ -2272,9 +2271,12 @@
     klass->SetStatus(Class::kStatusError);
     return NULL;
   }
-  interfaces_sfield->SetObject(NULL, interfaces);
-  throws_sfield->SetObject(NULL, throws);
-  klass->SetStatus(Class::kStatusInitialized);
+  {
+    ObjectLock lock(klass.get());  // Must hold lock on object when initializing.
+    interfaces_sfield->SetObject(NULL, interfaces);
+    throws_sfield->SetObject(NULL, throws);
+    klass->SetStatus(Class::kStatusInitialized);
+  }
 
   // sanity checks
   if (kIsDebugBuild) {
@@ -2663,10 +2665,8 @@
     Class* super_class = klass->GetSuperClass();
     if (super_class->GetStatus() != Class::kStatusInitialized) {
       CHECK(!super_class->IsInterface());
-      Thread* self = Thread::Current();
-      klass->MonitorEnter(self);
+      ObjectLock lock(klass);  // Must hold lock on object when initializing.
       bool super_initialized = InitializeClass(super_class, can_run_clinit, can_init_fields);
-      klass->MonitorExit(self);
       // TODO: check for a pending exception
       if (!super_initialized) {
         if (!can_run_clinit) {
diff --git a/src/class_linker.h b/src/class_linker.h
index c21ff71..3cee7f0 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -390,13 +390,11 @@
   InterfaceEntry* AllocInterfaceEntry(Class* interface)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  Class* CreatePrimitiveClass(const char* descriptor, Primitive::Type type)
+  Class* CreatePrimitiveClass(Primitive::Type type)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return InitializePrimitiveClass(AllocClass(sizeof(Class)), descriptor, type);
+    return InitializePrimitiveClass(AllocClass(sizeof(Class)), type);
   }
-  Class* InitializePrimitiveClass(Class* primitive_class,
-                                  const char* descriptor,
-                                  Primitive::Type type)
+  Class* InitializePrimitiveClass(Class* primitive_class, Primitive::Type type)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 
diff --git a/src/compiler.cc b/src/compiler.cc
index 69de8ca..b010750 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -481,11 +481,7 @@
 
   TimingLogger timings("compiler");
 
-  // TODO: make the verifier thread-safe and remove this workaround.
-  size_t thread_count = thread_count_;
-  thread_count_ = 1;
   PreCompile(class_loader, dex_files, timings);
-  thread_count_ = thread_count;
 
   Compile(class_loader, dex_files);
   timings.AddSplit("Compile");
diff --git a/src/object.cc b/src/object.cc
index cde7e04..dcf4ce9 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -612,6 +612,9 @@
   CHECK(new_status > GetStatus() || new_status == kStatusError || !Runtime::Current()->IsStarted())
       << PrettyClass(this) << " " << GetStatus() << " -> " << new_status;
   CHECK(sizeof(Status) == sizeof(uint32_t)) << PrettyClass(this);
+  if (new_status > kStatusResolved) {
+    CHECK_EQ(GetThinLockId(), Thread::Current()->GetThinLockId()) << PrettyClass(this);
+  }
   if (new_status == kStatusError) {
     CHECK_NE(GetStatus(), kStatusError) << PrettyClass(this);
 
diff --git a/src/verifier/method_verifier.cc b/src/verifier/method_verifier.cc
index 813073d..ce5129d 100644
--- a/src/verifier/method_verifier.cc
+++ b/src/verifier/method_verifier.cc
@@ -281,6 +281,9 @@
 MethodVerifier::FailureKind MethodVerifier::VerifyMethod(uint32_t method_idx, const DexFile* dex_file,
     DexCache* dex_cache, ClassLoader* class_loader, uint32_t class_def_idx,
     const DexFile::CodeItem* code_item, Method* method, uint32_t method_access_flags) {
+  MethodVerifier::FailureKind result = kNoFailure;
+  uint64_t start_ns = NanoTime();
+
   MethodVerifier verifier(dex_file, dex_cache, class_loader, class_def_idx, code_item, method_idx,
                           method, method_access_flags);
   if (verifier.Verify()) {
@@ -290,7 +293,7 @@
     if (verifier.failures_.size() != 0) {
       verifier.DumpFailures(LOG(INFO) << "Soft verification failures in "
                                       << PrettyMethod(method_idx, *dex_file) << "\n");
-      return kSoftFailure;
+      result = kSoftFailure;
     }
   } else {
     // Bad method data.
@@ -302,9 +305,14 @@
       std::cout << "\n" << verifier.info_messages_.str();
       verifier.Dump(std::cout);
     }
-    return kHardFailure;
+    result = kHardFailure;
   }
-  return kNoFailure;
+  uint64_t duration_ns = NanoTime() - start_ns;
+  if (duration_ns > MsToNs(100)) {
+    LOG(WARNING) << "Verification of " << PrettyMethod(method_idx, *dex_file)
+                 << " took " << PrettyDuration(duration_ns);
+  }
+  return result;
 }
 
 void MethodVerifier::VerifyMethodAndDump(Method* method) {