Don't allow class status to go backward except for error.

Allow greater parallelism of initialization.
Bug 10393546.

Change-Id: Ic194ed490bb0a986250c09fcf335eb1be9714657
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index bf541c6..d265ed1 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -758,11 +758,6 @@
   }
 }
 
-void CompilerDriver::RecordClassStatus(ClassReference ref, CompiledClass* compiled_class) {
-  MutexLock mu(Thread::Current(), CompilerDriver::compiled_classes_lock_);
-  compiled_classes_.Put(ref, compiled_class);
-}
-
 bool CompilerDriver::CanAssumeTypeIsPresentInDexCache(const DexFile& dex_file,
                                                       uint32_t type_idx) {
   if (IsImage() && IsImageClass(dex_file.GetTypeDescriptor(dex_file.GetTypeId(type_idx)))) {
@@ -1428,6 +1423,7 @@
 static void ResolveClassFieldsAndMethods(const ParallelCompilationManager* manager,
                                          size_t class_def_index)
     LOCKS_EXCLUDED(Locks::mutator_lock_) {
+  ATRACE_CALL();
   Thread* self = Thread::Current();
   jobject jclass_loader = manager->GetClassLoader();
   const DexFile& dex_file = *manager->GetDexFile();
@@ -2048,6 +2044,7 @@
 
 static void InitializeClass(const ParallelCompilationManager* manager, size_t class_def_index)
     LOCKS_EXCLUDED(Locks::mutator_lock_) {
+  ATRACE_CALL();
   const DexFile::ClassDef& class_def = manager->GetDexFile()->GetClassDef(class_def_index);
   ScopedObjectAccess soa(Thread::Current());
   mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(manager->GetClassLoader());
@@ -2056,48 +2053,54 @@
   if (klass != NULL) {
     // Only try to initialize classes that were successfully verified.
     if (klass->IsVerified()) {
-      // We don't want class initialization occurring on multiple threads due to deadlock problems.
-      // For example, a parent class is initialized (holding its lock) that refers to a sub-class
-      // in its static/class initializer causing it to try to acquire the sub-class' lock. While
-      // on a second thread the sub-class is initialized (holding its lock) after first initializing
-      // its parents, whose locks are acquired. This leads to a parent-to-child and a child-to-parent
-      // lock ordering and consequent potential deadlock.
-      // We need to use an ObjectLock due to potential suspension in the interpreting code. Rather
-      // than use a special Object for the purpose we use the Class of java.lang.Class.
-      ObjectLock lock(soa.Self(), klass->GetClass());
-      bool can_init_static_fields = manager->GetCompiler()->IsImage() &&
-          manager->GetCompiler()->IsImageClass(descriptor);
-      manager->GetClassLinker()->EnsureInitialized(klass, false, can_init_static_fields);
-      if (soa.Self()->IsExceptionPending()) {
-        soa.Self()->GetException(NULL)->Dump();
-      }
+      // Attempt to initialize the class but bail if we either need to initialize the super-class
+      // or static fields.
+      manager->GetClassLinker()->EnsureInitialized(klass, false, false);
       if (!klass->IsInitialized()) {
-        if (can_init_static_fields) {
-          // NoPreloadHolder inner class implies this should not be initialized early.
-          bool is_black_listed = StringPiece(descriptor).ends_with("$NoPreloadHolder;");
-          if (!is_black_listed) {
-            for (size_t i = 0; i < arraysize(class_initializer_black_list); ++i) {
-              if (StringPiece(descriptor) == class_initializer_black_list[i]) {
-                is_black_listed = true;
-                break;
+        // We don't want non-trivial class initialization occurring on multiple threads due to
+        // deadlock problems. For example, a parent class is initialized (holding its lock) that
+        // refers to a sub-class in its static/class initializer causing it to try to acquire the
+        // sub-class' lock. While on a second thread the sub-class is initialized (holding its lock)
+        // after first initializing its parents, whose locks are acquired. This leads to a
+        // parent-to-child and a child-to-parent lock ordering and consequent potential deadlock.
+        // We need to use an ObjectLock due to potential suspension in the interpreting code. Rather
+        // than use a special Object for the purpose we use the Class of java.lang.Class.
+        ObjectLock lock(soa.Self(), klass->GetClass());
+        // Attempt to initialize allowing initialization of parent classes but still not static
+        // fields.
+        manager->GetClassLinker()->EnsureInitialized(klass, false, true);
+        if (!klass->IsInitialized()) {
+          // We need to initialize static fields, we only do this for image classes that aren't
+          // black listed or marked with the $NoPreloadHolder.
+          bool can_init_static_fields = manager->GetCompiler()->IsImage() &&
+              manager->GetCompiler()->IsImageClass(descriptor);
+          if (can_init_static_fields) {
+            // NoPreloadHolder inner class implies this should not be initialized early.
+            bool is_black_listed = StringPiece(descriptor).ends_with("$NoPreloadHolder;");
+            if (!is_black_listed) {
+              for (size_t i = 0; i < arraysize(class_initializer_black_list); ++i) {
+                if (StringPiece(descriptor) == class_initializer_black_list[i]) {
+                  is_black_listed = true;
+                  break;
+                }
+              }
+            }
+            if (!is_black_listed) {
+              VLOG(compiler) << "Initializing: " << descriptor;
+              if (StringPiece(descriptor) == "Ljava/lang/Void;") {
+                // Hand initialize j.l.Void to avoid Dex file operations in un-started runtime.
+                ObjectLock lock(soa.Self(), klass);
+                mirror::ObjectArray<mirror::ArtField>* fields = klass->GetSFields();
+                CHECK_EQ(fields->GetLength(), 1);
+                fields->Get(0)->SetObj(klass, manager->GetClassLinker()->FindPrimitiveClass('V'));
+                klass->SetStatus(mirror::Class::kStatusInitialized);
+              } else {
+                manager->GetClassLinker()->EnsureInitialized(klass, true, true);
               }
             }
           }
-          if (!is_black_listed) {
-            VLOG(compiler) << "Initializing: " << descriptor;
-            if (StringPiece(descriptor) == "Ljava/lang/Void;") {
-              // Hand initialize j.l.Void to avoid Dex file operations in un-started runtime.
-              ObjectLock lock(soa.Self(), klass);
-              mirror::ObjectArray<mirror::ArtField>* fields = klass->GetSFields();
-              CHECK_EQ(fields->GetLength(), 1);
-              fields->Get(0)->SetObj(klass, manager->GetClassLinker()->FindPrimitiveClass('V'));
-              klass->SetStatus(mirror::Class::kStatusInitialized);
-            } else {
-              manager->GetClassLinker()->EnsureInitialized(klass, true, can_init_static_fields);
-            }
-            soa.Self()->AssertNoPendingException();
-          }
         }
+        soa.Self()->AssertNoPendingException();
       }
       // If successfully initialized place in SSB array.
       if (klass->IsInitialized()) {
@@ -2105,15 +2108,8 @@
       }
     }
     // Record the final class status if necessary.
-    mirror::Class::Status status = klass->GetStatus();
     ClassReference ref(manager->GetDexFile(), class_def_index);
-    CompiledClass* compiled_class = manager->GetCompiler()->GetCompiledClass(ref);
-    if (compiled_class == NULL) {
-      compiled_class = new CompiledClass(status);
-      manager->GetCompiler()->RecordClassStatus(ref, compiled_class);
-    } else {
-      DCHECK_GE(status, compiled_class->GetStatus()) << descriptor;
-    }
+    manager->GetCompiler()->RecordClassStatus(ref, klass->GetStatus());
   }
   // Clear any class not found or verification exceptions.
   soa.Self()->ClearException();
@@ -2288,7 +2284,7 @@
   Thread* self = Thread::Current();
   if (compiled_method != NULL) {
     MethodReference ref(&dex_file, method_idx);
-    CHECK(GetCompiledMethod(ref) == NULL) << PrettyMethod(method_idx, dex_file);
+    DCHECK(GetCompiledMethod(ref) == NULL) << PrettyMethod(method_idx, dex_file);
     {
       MutexLock mu(self, compiled_methods_lock_);
       compiled_methods_.Put(ref, compiled_method);
@@ -2313,6 +2309,32 @@
   return it->second;
 }
 
+void CompilerDriver::RecordClassStatus(ClassReference ref, mirror::Class::Status status) {
+  MutexLock mu(Thread::Current(), compiled_classes_lock_);
+  auto it = compiled_classes_.find(ref);
+  if (it == compiled_classes_.end() || it->second->GetStatus() != status) {
+    // An entry doesn't exist or the status is lower than the new status.
+    if (it != compiled_classes_.end()) {
+      CHECK_GT(status, it->second->GetStatus());
+      delete it->second;
+    }
+    switch (status) {
+      case mirror::Class::kStatusNotReady:
+      case mirror::Class::kStatusError:
+      case mirror::Class::kStatusRetryVerificationAtRuntime:
+      case mirror::Class::kStatusVerified:
+      case mirror::Class::kStatusInitialized:
+        break;  // Expected states.
+      default:
+        LOG(FATAL) << "Unexpected class status for class "
+            << PrettyDescriptor(ref.first->GetClassDescriptor(ref.first->GetClassDef(ref.second)))
+            << " of " << status;
+    }
+    CompiledClass* compiled_class = new CompiledClass(status);
+    compiled_classes_.Overwrite(ref, compiled_class);
+  }
+}
+
 CompiledMethod* CompilerDriver::GetCompiledMethod(MethodReference ref) const {
   MutexLock mu(Thread::Current(), compiled_methods_lock_);
   MethodTable::const_iterator it = compiled_methods_.find(ref);
@@ -2335,13 +2357,13 @@
 
 void CompilerDriver::AddRequiresConstructorBarrier(Thread* self, const DexFile* dex_file,
                                              size_t class_def_index) {
-  MutexLock mu(self, freezing_constructor_lock_);
+  WriterMutexLock mu(self, freezing_constructor_lock_);
   freezing_constructor_classes_.insert(ClassReference(dex_file, class_def_index));
 }
 
 bool CompilerDriver::RequiresConstructorBarrier(Thread* self, const DexFile* dex_file,
                                           size_t class_def_index) {
-  MutexLock mu(self, freezing_constructor_lock_);
+  ReaderMutexLock mu(self, freezing_constructor_lock_);
   return freezing_constructor_classes_.count(ClassReference(dex_file, class_def_index)) != 0;
 }
 
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index bcde178..22a510b 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -296,7 +296,8 @@
   // Checks if class specified by type_idx is one of the image_classes_
   bool IsImageClass(const char* descriptor) const;
 
-  void RecordClassStatus(ClassReference ref, CompiledClass* compiled_class);
+  void RecordClassStatus(ClassReference ref, mirror::Class::Status status)
+      LOCKS_EXCLUDED(compiled_classes_lock_);
 
  private:
   // Compute constant code and method pointers when possible
@@ -362,7 +363,7 @@
   InstructionSet instruction_set_;
 
   // All class references that require
-  mutable Mutex freezing_constructor_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+  mutable ReaderWriterMutex freezing_constructor_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
   std::set<ClassReference> freezing_constructor_classes_ GUARDED_BY(freezing_constructor_lock_);
 
   typedef SafeMap<const ClassReference, CompiledClass*> ClassTable;
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 0110b36..96c7420 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -782,8 +782,10 @@
   }
 
   ~ScopedFlock() {
-    int flock_result = TEMP_FAILURE_RETRY(flock(file_->Fd(), LOCK_UN));
-    CHECK_EQ(0, flock_result);
+    if (file_.get() != NULL) {
+      int flock_result = TEMP_FAILURE_RETRY(flock(file_->Fd(), LOCK_UN));
+      CHECK_EQ(0, flock_result);
+    }
   }
 
  private:
@@ -2284,18 +2286,18 @@
   }
 
   // Verify super class.
-  mirror::Class* super = klass->GetSuperClass();
-  if (super != NULL) {
+  SirtRef<mirror::Class> super(self, klass->GetSuperClass());
+  if (super.get() != NULL) {
     // Acquire lock to prevent races on verifying the super class.
-    ObjectLock lock(self, super);
+    ObjectLock lock(self, super.get());
 
     if (!super->IsVerified() && !super->IsErroneous()) {
-      Runtime::Current()->GetClassLinker()->VerifyClass(super);
+      VerifyClass(super.get());
     }
     if (!super->IsCompileTimeVerified()) {
       std::string error_msg(StringPrintf("Rejecting class %s that attempts to sub-class erroneous class %s",
                                          PrettyDescriptor(klass).c_str(),
-                                         PrettyDescriptor(super).c_str()));
+                                         PrettyDescriptor(super.get()).c_str()));
       LOG(ERROR) << error_msg  << " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8();
       SirtRef<mirror::Throwable> cause(self, self->GetException(NULL));
       if (cause.get() != NULL) {
@@ -2339,7 +2341,14 @@
     // Make sure all classes referenced by catch blocks are resolved.
     ResolveClassExceptionHandlerTypes(dex_file, klass);
     if (verifier_failure == verifier::MethodVerifier::kNoFailure) {
-      klass->SetStatus(mirror::Class::kStatusVerified);
+      // Even though there were no verifier failures we need to respect whether the super-class
+      // was verified or requiring runtime reverification.
+      if (super.get() == NULL || super->IsVerified()) {
+        klass->SetStatus(mirror::Class::kStatusVerified);
+      } else {
+        CHECK_EQ(super->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime);
+        klass->SetStatus(mirror::Class::kStatusRetryVerificationAtRuntime);
+      }
     } else {
       CHECK_EQ(verifier_failure, verifier::MethodVerifier::kSoftFailure);
       // Soft failures at compile time should be retried at runtime. Soft
@@ -2695,31 +2704,85 @@
   CHECK_EQ(mh.GetReturnType(), mh2.GetReturnType());
 }
 
-bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_run_clinit, bool can_init_statics) {
-  CHECK(klass->IsResolved() || klass->IsErroneous())
-      << PrettyClass(klass) << ": state=" << klass->GetStatus();
+static bool CanWeInitializeClass(mirror::Class* klass, bool can_init_statics,
+                                 bool can_init_parents)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  if (can_init_statics && can_init_statics) {
+    return true;
+  }
+  if (!can_init_statics) {
+    // Check if there's a class initializer.
+    mirror::ArtMethod* clinit = klass->FindDeclaredDirectMethod("<clinit>", "()V");
+    if (clinit != NULL) {
+      return false;
+    }
+    // Check if there are encoded static values needing initialization.
+    if (klass->NumStaticFields() != 0) {
+      ClassHelper kh(klass);
+      const DexFile::ClassDef* dex_class_def = kh.GetClassDef();
+      DCHECK(dex_class_def != NULL);
+      if (dex_class_def->static_values_off_ != 0) {
+        return false;
+      }
+    }
+  }
+  if (!klass->IsInterface() && klass->HasSuperClass()) {
+    mirror::Class* super_class = klass->GetSuperClass();
+    if (!can_init_parents && !super_class->IsInitialized()) {
+      return false;
+    } else {
+      if (!CanWeInitializeClass(super_class, can_init_statics, true)) {
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics,
+                                  bool can_init_parents) {
+  // see JLS 3rd edition, 12.4.2 "Detailed Initialization Procedure" for the locking protocol
+
+  // Are we already initialized and therefore done?
+  // Note: we differ from the JLS here as we don't do this under the lock, this is benign as
+  // an initialized class will never change its state.
+  if (klass->IsInitialized()) {
+    return true;
+  }
+
+  // Fast fail if initialization requires a full runtime. Not part of the JLS.
+  if (!CanWeInitializeClass(klass, can_init_statics, can_init_parents)) {
+    return false;
+  }
 
   Thread* self = Thread::Current();
-
+  uint64_t t0;
   {
-    // see JLS 3rd edition, 12.4.2 "Detailed Initialization Procedure" for the locking protocol
     ObjectLock lock(self, klass);
 
-    if (klass->GetStatus() == mirror::Class::kStatusInitialized) {
+    // Re-check under the lock in case another thread initialized ahead of us.
+    if (klass->IsInitialized()) {
       return true;
     }
 
+    // Was the class already found to be erroneous? Done under the lock to match the JLS.
     if (klass->IsErroneous()) {
       ThrowEarlierClassFailure(klass);
       return false;
     }
 
-    if (klass->GetStatus() == mirror::Class::kStatusResolved ||
-        klass->GetStatus() == mirror::Class::kStatusRetryVerificationAtRuntime) {
+    CHECK(klass->IsResolved()) << PrettyClass(klass) << ": state=" << klass->GetStatus();
+
+    if (!klass->IsVerified()) {
       VerifyClass(klass);
-      if (klass->GetStatus() != mirror::Class::kStatusVerified) {
-        if (klass->GetStatus() == mirror::Class::kStatusError) {
+      if (!klass->IsVerified()) {
+        // We failed to verify, expect either the klass to be erroneous or verification failed at
+        // compile time.
+        if (klass->IsErroneous()) {
           CHECK(self->IsExceptionPending());
+        } else {
+          CHECK(Runtime::Current()->IsCompiler());
+          CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime);
         }
         return false;
       }
@@ -2742,38 +2805,65 @@
 
     if (!ValidateSuperClassDescriptors(klass)) {
       klass->SetStatus(mirror::Class::kStatusError);
-      lock.NotifyAll();
       return false;
     }
 
-    DCHECK_EQ(klass->GetStatus(), mirror::Class::kStatusVerified) << PrettyClass(klass);
+    CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusVerified) << PrettyClass(klass);
 
+    // From here out other threads may observe that we're initializing and so changes of state
+    // require the a notification.
     klass->SetClinitThreadId(self->GetTid());
     klass->SetStatus(mirror::Class::kStatusInitializing);
+
+    t0 = NanoTime();
   }
 
-  uint64_t t0 = NanoTime();
-
-  if (!InitializeSuperClass(klass, can_run_clinit, can_init_statics)) {
-    // Super class initialization failed, this can be because we can't run
-    // super-class class initializers in which case we'll be verified.
-    // Otherwise this class is erroneous.
-    if (!can_run_clinit) {
-      CHECK(klass->IsVerified());
-    } else {
-      CHECK(klass->IsErroneous());
+  // Initialize super classes, must be done will initializing for the JLS.
+  if (!klass->IsInterface() && klass->HasSuperClass()) {
+    mirror::Class* super_class = klass->GetSuperClass();
+    if (!super_class->IsInitialized()) {
+      CHECK(!super_class->IsInterface());
+      CHECK(can_init_parents);
+      bool super_initialized = InitializeClass(super_class, can_init_statics, true);
+      if (!super_initialized) {
+        // The super class was verified ahead of entering initializing, we should only be here if
+        // the super class became erroneous due to initialization.
+        CHECK(super_class->IsErroneous() && self->IsExceptionPending())
+            << "Super class initialization failed for " << PrettyDescriptor(super_class)
+            << " that has unexpected status " << super_class->GetStatus()
+            << "\nPending exception:\n"
+            << (self->GetException(NULL) != NULL ? self->GetException(NULL)->Dump() : "");
+        ObjectLock lock(self, klass);
+        // Initialization failed because the super-class is erroneous.
+        klass->SetStatus(mirror::Class::kStatusError);
+        lock.NotifyAll();
+        return false;
+      }
     }
-    // Signal to any waiting threads that saw this class as initializing.
-    ObjectLock lock(self, klass);
-    lock.NotifyAll();
-    return false;
   }
 
-  bool has_static_field_initializers = InitializeStaticFields(klass, can_init_statics);
+  if (klass->NumStaticFields() > 0) {
+    ClassHelper kh(klass);
+    const DexFile::ClassDef* dex_class_def = kh.GetClassDef();
+    CHECK(dex_class_def != NULL);
+    const DexFile& dex_file = kh.GetDexFile();
+    EncodedStaticFieldValueIterator it(dex_file, kh.GetDexCache(), klass->GetClassLoader(),
+                                       this, *dex_class_def);
+    if (it.HasNext()) {
+      CHECK(can_init_statics);
+      // We reordered the fields, so we need to be able to map the field indexes to the right fields.
+      SafeMap<uint32_t, mirror::ArtField*> field_map;
+      ConstructFieldMap(dex_file, *dex_class_def, klass, field_map);
+      for (size_t i = 0; it.HasNext(); i++, it.Next()) {
+        it.ReadValueToField(field_map.Get(i));
+      }
+    }
+  }
 
   mirror::ArtMethod* clinit = klass->FindDeclaredDirectMethod("<clinit>", "()V");
-  if (clinit != NULL && can_run_clinit) {
-    if (Runtime::Current()->IsStarted()) {
+  if (clinit != NULL) {
+    CHECK(can_init_statics);
+    if (LIKELY(Runtime::Current()->IsStarted())) {
       JValue result;
       clinit->Invoke(self, NULL, 0, &result, 'V');
     } else {
@@ -2781,11 +2871,8 @@
     }
   }
 
-  // Opportunistically set static method trampolines to their destination. Unless initialization
-  // is being hindered at compile time.
-  if (can_init_statics || can_run_clinit || (!has_static_field_initializers && clinit == NULL)) {
-    FixupStaticTrampolines(klass);
-  }
+  // Opportunistically set static method trampolines to their destination.
+  FixupStaticTrampolines(klass);
 
   uint64_t t1 = NanoTime();
 
@@ -2805,14 +2892,8 @@
       global_stats->class_init_time_ns += (t1 - t0);
       thread_stats->class_init_time_ns += (t1 - t0);
       // Set the class as initialized except if failed to initialize static fields.
-      if ((!can_init_statics && has_static_field_initializers) ||
-          (!can_run_clinit && clinit != NULL)) {
-        klass->SetStatus(mirror::Class::kStatusVerified);
-        success = false;
-      } else {
-        klass->SetStatus(mirror::Class::kStatusInitialized);
-      }
-      if (success && VLOG_IS_ON(class_linker)) {
+      klass->SetStatus(mirror::Class::kStatusInitialized);
+      if (VLOG_IS_ON(class_linker)) {
         ClassHelper kh(klass);
         LOG(INFO) << "Initialized class " << kh.GetDescriptor() << " from " << kh.GetLocation();
       }
@@ -2826,6 +2907,7 @@
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   while (true) {
     self->AssertNoPendingException();
+    CHECK(!klass->IsInitialized());
     lock.WaitIgnoringInterrupts();
 
     // When we wake up, repeat the test for init-in-progress.  If
@@ -2952,43 +3034,16 @@
   return found1 == found2;
 }
 
-bool ClassLinker::InitializeSuperClass(mirror::Class* klass, bool can_run_clinit, bool can_init_fields) {
-  CHECK(klass != NULL);
-  if (!klass->IsInterface() && klass->HasSuperClass()) {
-    mirror::Class* super_class = klass->GetSuperClass();
-    if (!super_class->IsInitialized()) {
-      CHECK(!super_class->IsInterface());
-      // Must hold lock on object when initializing and setting status.
-      Thread* self = Thread::Current();
-      ObjectLock lock(self, klass);
-      bool super_initialized = InitializeClass(super_class, can_run_clinit, can_init_fields);
-      // TODO: check for a pending exception
-      if (!super_initialized) {
-        if (!can_run_clinit) {
-          // Don't set status to error when we can't run <clinit>.
-          CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusInitializing) << PrettyClass(klass);
-          klass->SetStatus(mirror::Class::kStatusVerified);
-          return false;
-        }
-        klass->SetStatus(mirror::Class::kStatusError);
-        klass->NotifyAll(self);
-        return false;
-      }
-    }
-  }
-  return true;
-}
-
-bool ClassLinker::EnsureInitialized(mirror::Class* c, bool can_run_clinit, bool can_init_fields) {
+bool ClassLinker::EnsureInitialized(mirror::Class* c, bool can_init_fields, bool can_init_parents) {
   DCHECK(c != NULL);
   if (c->IsInitialized()) {
     return true;
   }
 
-  bool success = InitializeClass(c, can_run_clinit, can_init_fields);
+  bool success = InitializeClass(c, can_init_fields, can_init_parents);
   if (!success) {
     Thread* self = Thread::Current();
-    CHECK(self->IsExceptionPending() || !can_run_clinit) << PrettyClass(c);
+    CHECK(self->IsExceptionPending() || !can_init_fields || !can_init_parents) << PrettyClass(c);
   }
   return success;
 }
@@ -3003,38 +3058,6 @@
   }
 }
 
-bool ClassLinker::InitializeStaticFields(mirror::Class* klass, bool can_init_statics) {
-  size_t num_static_fields = klass->NumStaticFields();
-  if (num_static_fields == 0) {
-    return false;
-  }
-  mirror::DexCache* dex_cache = klass->GetDexCache();
-  // TODO: this seems like the wrong check. do we really want !IsPrimitive && !IsArray?
-  if (dex_cache == NULL) {
-    return false;
-  }
-  ClassHelper kh(klass);
-  const DexFile::ClassDef* dex_class_def = kh.GetClassDef();
-  CHECK(dex_class_def != NULL);
-  const DexFile& dex_file = kh.GetDexFile();
-  EncodedStaticFieldValueIterator it(dex_file, dex_cache, klass->GetClassLoader(),
-                                     this, *dex_class_def);
-
-  if (!it.HasNext()) {
-    return false;
-  } else {
-    if (can_init_statics) {
-      // We reordered the fields, so we need to be able to map the field indexes to the right fields.
-      SafeMap<uint32_t, mirror::ArtField*> field_map;
-      ConstructFieldMap(dex_file, *dex_class_def, klass, field_map);
-      for (size_t i = 0; it.HasNext(); i++, it.Next()) {
-        it.ReadValueToField(field_map.Get(i));
-      }
-    }
-    return true;
-  }
-}
-
 bool ClassLinker::LinkClass(SirtRef<mirror::Class>& klass,
                             mirror::ObjectArray<mirror::Class>* interfaces) {
   CHECK_EQ(mirror::Class::kStatusLoaded, klass->GetStatus());
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 624b7ce..5ef6d8f 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -437,16 +437,11 @@
   void RegisterOatFileLocked(const OatFile& oat_file) EXCLUSIVE_LOCKS_REQUIRED(dex_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(dex_lock_);
 
-  bool InitializeClass(mirror::Class* klass, bool can_run_clinit, bool can_init_statics)
+  bool InitializeClass(mirror::Class* klass, bool can_run_clinit, bool can_init_parents)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   bool WaitForInitializeClass(mirror::Class* klass, Thread* self, ObjectLock& lock);
   bool ValidateSuperClassDescriptors(const mirror::Class* klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  bool InitializeSuperClass(mirror::Class* klass, bool can_run_clinit, bool can_init_fields)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  // Initialize static fields, returns true if fields were initialized.
-  bool InitializeStaticFields(mirror::Class* klass, bool can_init_statics)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   bool IsSameDescriptorInDifferentClassContexts(const char* descriptor,
                                                 const mirror::Class* klass1,
diff --git a/runtime/exception_test.cc b/runtime/exception_test.cc
index e48208d..2e6b0a8 100644
--- a/runtime/exception_test.cc
+++ b/runtime/exception_test.cc
@@ -41,7 +41,7 @@
                                       soa.Decode<mirror::ClassLoader*>(LoadDex("ExceptionHandle")));
     my_klass_ = class_linker_->FindClass("LExceptionHandle;", class_loader.get());
     ASSERT_TRUE(my_klass_ != NULL);
-    class_linker_->EnsureInitialized(my_klass_, false, true);
+    class_linker_->EnsureInitialized(my_klass_, true, true);
 
     dex_ = my_klass_->GetDexCache()->GetDexFile();
 
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 29025f2..19e134f 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -51,14 +51,20 @@
 }
 
 void Class::SetStatus(Status new_status) {
-  CHECK(new_status > GetStatus() || new_status == kStatusError || !Runtime::Current()->IsStarted())
-      << PrettyClass(this) << " " << GetStatus() << " -> " << new_status;
-  CHECK(sizeof(Status) == sizeof(uint32_t)) << PrettyClass(this);
+  if (UNLIKELY(new_status <= GetStatus() && new_status != kStatusError)) {
+    bool class_linker_initialized = Runtime::Current()->GetClassLinker() != nullptr;
+    if (class_linker_initialized) {
+      LOG(FATAL) << "Unexpected change back of class status for " << PrettyClass(this) << " "
+          << GetStatus() << " -> " << new_status;
+    }
+  }
   if (new_status > kStatusResolved) {
-    CHECK_EQ(GetThinLockId(), Thread::Current()->GetThinLockId()) << PrettyClass(this);
+    CHECK_EQ(GetThinLockId(), Thread::Current()->GetThinLockId())
+        << "Attempt to change status of class while not holding its lock " << PrettyClass(this);
   }
   if (new_status == kStatusError) {
-    CHECK_NE(GetStatus(), kStatusError) << PrettyClass(this);
+    CHECK_NE(GetStatus(), kStatusError)
+        << "Attempt to set as erroneous an already erroneous class " << PrettyClass(this);
 
     // Stash current exception.
     Thread* self = Thread::Current();
@@ -96,6 +102,7 @@
 
     self->SetException(gc_safe_throw_location, old_exception.get());
   }
+  CHECK(sizeof(Status) == sizeof(uint32_t)) << PrettyClass(this);
   return SetField32(OFFSET_OF_OBJECT_MEMBER(Class, status_), new_status, false);
 }