Merge "Add missing class initialization during compilation and tests"
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 80e7724..72c34b4 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -467,6 +467,7 @@
       }
     }
     runtime->GetClassLinker()->FixupDexCaches(runtime->GetResolutionMethod());
+    runtime->GetClassLinker()->RunRootClinits();
     runtime_ = runtime;
     return true;
   }
diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h
index 289dc1d..ac6d44b 100644
--- a/runtime/common_runtime_test.h
+++ b/runtime/common_runtime_test.h
@@ -206,6 +206,7 @@
     runtime_.reset(Runtime::Current());
     class_linker_ = runtime_->GetClassLinker();
     class_linker_->FixupDexCaches(runtime_->GetResolutionMethod());
+    class_linker_->RunRootClinits();
 
     // Runtime::Create acquired the mutator_lock_ that is normally given away when we
     // Runtime::Start, give it away now and then switch to a more managable ScopedObjectAccess.
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 729444e..2db62f8 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -356,6 +356,7 @@
          shadow_frame.GetMethod()->GetDeclaringClass()->IsProxyClass());
   DCHECK(!shadow_frame.GetMethod()->IsAbstract());
   DCHECK(!shadow_frame.GetMethod()->IsNative());
+  shadow_frame.GetMethod()->GetDeclaringClass()->AssertInitializedOrInitializingInThread(self);
 
   bool transaction_active = Runtime::Current()->IsActiveTransaction();
   if (LIKELY(shadow_frame.GetMethod()->IsPreverified())) {
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 9f04b90..5a03601 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -35,6 +35,7 @@
     CHECK(self->IsExceptionPending());
     return false;
   }
+  f->GetDeclaringClass()->AssertInitializedOrInitializingInThread(self);
   Object* obj;
   if (is_static) {
     obj = f->GetDeclaringClass();
@@ -210,6 +211,7 @@
     CHECK(self->IsExceptionPending());
     return false;
   }
+  f->GetDeclaringClass()->AssertInitializedOrInitializingInThread(self);
   Object* obj;
   if (is_static) {
     obj = f->GetDeclaringClass();
@@ -757,40 +759,64 @@
   }
 }
 
+// Helper function to deal with class loading in an unstarted runtime.
+static void UnstartedRuntimeFindClass(Thread* self, Handle<mirror::String> className,
+                                      Handle<mirror::ClassLoader> class_loader, JValue* result,
+                                      const std::string& method_name, bool initialize_class,
+                                      bool abort_if_not_found)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  CHECK(className.Get() != nullptr);
+  std::string descriptor(DotToDescriptor(className->ToModifiedUtf8().c_str()));
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+
+  Class* found = class_linker->FindClass(self, descriptor.c_str(), class_loader);
+  if (found == nullptr && abort_if_not_found) {
+    if (!self->IsExceptionPending()) {
+      AbortTransaction(self, "%s failed in un-started runtime for class: %s",
+                       method_name.c_str(), PrettyDescriptor(descriptor).c_str());
+    }
+    return;
+  }
+  if (found != nullptr && initialize_class) {
+    StackHandleScope<1> hs(self);
+    Handle<mirror::Class> h_class(hs.NewHandle(found));
+    if (!class_linker->EnsureInitialized(h_class, true, true)) {
+      CHECK(self->IsExceptionPending());
+      return;
+    }
+  }
+  result->SetL(found);
+}
+
 static void UnstartedRuntimeInvoke(Thread* self, MethodHelper& mh,
                                    const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame,
                                    JValue* result, size_t arg_offset) {
   // In a runtime that's not started we intercept certain methods to avoid complicated dependency
   // problems in core libraries.
   std::string name(PrettyMethod(shadow_frame->GetMethod()));
-  if (name == "java.lang.Class java.lang.Class.forName(java.lang.String)"
-      || name == "java.lang.Class java.lang.VMClassLoader.loadClass(java.lang.String, boolean)") {
-    // TODO Class#forName should actually call Class::EnsureInitialized always. Support for the
-    // other variants that take more arguments should also be added.
-    std::string descriptor(DotToDescriptor(shadow_frame->GetVRegReference(arg_offset)->AsString()->ToModifiedUtf8().c_str()));
-
-    // shadow_frame.GetMethod()->GetDeclaringClass()->GetClassLoader();
-    Class* found = Runtime::Current()->GetClassLinker()->FindClass(
-        self, descriptor.c_str(), NullHandle<mirror::ClassLoader>());
-    if (found == NULL) {
-      if (!self->IsExceptionPending()) {
-        AbortTransaction(self, "Class.forName failed in un-started runtime for class: %s",
-                         PrettyDescriptor(descriptor).c_str());
-      }
-      return;
-    }
-    result->SetL(found);
+  if (name == "java.lang.Class java.lang.Class.forName(java.lang.String)") {
+    // TODO: Support for the other variants that take more arguments should also be added.
+    mirror::String* class_name = shadow_frame->GetVRegReference(arg_offset)->AsString();
+    StackHandleScope<1> hs(self);
+    Handle<mirror::String> h_class_name(hs.NewHandle(class_name));
+    UnstartedRuntimeFindClass(self, h_class_name, NullHandle<mirror::ClassLoader>(), result, name,
+                              true, true);
+  } else if (name == "java.lang.Class java.lang.VMClassLoader.loadClass(java.lang.String, boolean)") {
+    mirror::String* class_name = shadow_frame->GetVRegReference(arg_offset)->AsString();
+    StackHandleScope<1> hs(self);
+    Handle<mirror::String> h_class_name(hs.NewHandle(class_name));
+    UnstartedRuntimeFindClass(self, h_class_name, NullHandle<mirror::ClassLoader>(), result, name,
+                              false, true);
+  } else if (name == "java.lang.Class java.lang.VMClassLoader.findLoadedClass(java.lang.ClassLoader, java.lang.String)") {
+    mirror::String* class_name = shadow_frame->GetVRegReference(arg_offset + 1)->AsString();
+    mirror::ClassLoader* class_loader =
+        down_cast<mirror::ClassLoader*>(shadow_frame->GetVRegReference(arg_offset));
+    StackHandleScope<2> hs(self);
+    Handle<mirror::String> h_class_name(hs.NewHandle(class_name));
+    Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(class_loader));
+    UnstartedRuntimeFindClass(self, h_class_name, h_class_loader, result, name, false, false);
   } else if (name == "java.lang.Class java.lang.Void.lookupType()") {
     result->SetL(Runtime::Current()->GetClassLinker()->FindPrimitiveClass('V'));
-  } else if (name == "java.lang.Class java.lang.VMClassLoader.findLoadedClass(java.lang.ClassLoader, java.lang.String)") {
-    StackHandleScope<1> hs(self);
-    Handle<ClassLoader> class_loader(
-        hs.NewHandle(down_cast<mirror::ClassLoader*>(shadow_frame->GetVRegReference(arg_offset))));
-    std::string descriptor(DotToDescriptor(shadow_frame->GetVRegReference(arg_offset + 1)->AsString()->ToModifiedUtf8().c_str()));
-
-    Class* found = Runtime::Current()->GetClassLinker()->FindClass(self, descriptor.c_str(),
-                                                                   class_loader);
-    result->SetL(found);
   } else if (name == "java.lang.Object java.lang.Class.newInstance()") {
     Class* klass = shadow_frame->GetVRegReference(arg_offset)->AsClass();
     ArtMethod* c = klass->FindDeclaredDirectMethod("<init>", "()V");
diff --git a/runtime/interpreter/interpreter_goto_table_impl.cc b/runtime/interpreter/interpreter_goto_table_impl.cc
index cb4868c..abd4b44 100644
--- a/runtime/interpreter/interpreter_goto_table_impl.cc
+++ b/runtime/interpreter/interpreter_goto_table_impl.cc
@@ -536,6 +536,7 @@
     if (UNLIKELY(obj == NULL)) {
       HANDLE_PENDING_EXCEPTION();
     } else {
+      obj->GetClass()->AssertInitializedOrInitializingInThread(self);
       // Don't allow finalizable objects to be allocated during a transaction since these can't be
       // finalized without a started runtime.
       if (transaction_active && obj->GetClass()->IsFinalizable()) {
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index bdf2a20..c635648 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -449,6 +449,7 @@
         if (UNLIKELY(obj == NULL)) {
           HANDLE_PENDING_EXCEPTION();
         } else {
+          obj->GetClass()->AssertInitializedOrInitializingInThread(self);
           // Don't allow finalizable objects to be allocated during a transaction since these can't
           // be finalized without a started runtime.
           if (transaction_active && obj->GetClass()->IsFinalizable()) {
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 451235c..2daa6e4 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -546,6 +546,14 @@
   }
 }
 
+inline void Class::AssertInitializedOrInitializingInThread(Thread* self) {
+  if (kIsDebugBuild && !IsInitialized()) {
+    CHECK(IsInitializing()) << PrettyClass(this) << " is not initializing: " << GetStatus();
+    CHECK_EQ(GetClinitThreadId(), self->GetTid()) << PrettyClass(this)
+                                                  << " is initializing in a different thread";
+  }
+}
+
 }  // namespace mirror
 }  // namespace art
 
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index e735c45..7ac53ea 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -880,6 +880,10 @@
   const DexFile& GetDexFile() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   const DexFile::TypeList* GetInterfaceTypeList() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  // Asserts we are initialized or initializing in the given thread.
+  void AssertInitializedOrInitializingInThread(Thread* self)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
  private:
   void SetVerifyErrorClass(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
diff --git a/runtime/oat.cc b/runtime/oat.cc
index 857c0a2..7c8e5bc 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -22,7 +22,7 @@
 namespace art {
 
 const uint8_t OatHeader::kOatMagic[] = { 'o', 'a', 't', '\n' };
-const uint8_t OatHeader::kOatVersion[] = { '0', '3', '6', '\0' };
+const uint8_t OatHeader::kOatVersion[] = { '0', '3', '7', '\0' };
 
 OatHeader::OatHeader() {
   memset(this, 0, sizeof(*this));
diff --git a/runtime/reflection_test.cc b/runtime/reflection_test.cc
index 3b66abe..abe68ef 100644
--- a/runtime/reflection_test.cc
+++ b/runtime/reflection_test.cc
@@ -109,7 +109,16 @@
                         : c->FindVirtualMethod(method_name, method_signature);
     CHECK(method != nullptr);
 
-    *receiver = (is_static ? nullptr : c->AllocObject(self));
+    if (is_static) {
+      *receiver = nullptr;
+    } else {
+      // Ensure class is initialized before allocating object
+      StackHandleScope<1> hs(self);
+      Handle<mirror::Class> h_class(hs.NewHandle(c));
+      bool initialized = class_linker_->EnsureInitialized(h_class, true, true);
+      CHECK(initialized);
+      *receiver = c->AllocObject(self);
+    }
 
     // Start runtime.
     bool started = runtime_->Start();