Clinits may not have the kAccConstructor flag.

Bug: 11157540
Set the clinit access flag when we load the method and warn about badly
formed access flags.

Change-Id: I515c692095051f84f98510722ab764591185918e
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index f0a7202..28c9a56 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1866,47 +1866,54 @@
   const char* old_cause = self->StartAssertNoThreadSuspension("LoadMethod");
   dst->SetDexMethodIndex(dex_method_idx);
   dst->SetDeclaringClass(klass.get());
-
-  if (method_name == "finalize") {
-    // Create the prototype for a signature of "()V"
-    const DexFile::StringId* void_string_id = dex_file.FindStringId("V");
-    if (void_string_id != NULL) {
-      const DexFile::TypeId* void_type_id =
-          dex_file.FindTypeId(dex_file.GetIndexForStringId(*void_string_id));
-      if (void_type_id != NULL) {
-        std::vector<uint16_t> no_args;
-        const DexFile::ProtoId* finalizer_proto =
-            dex_file.FindProtoId(dex_file.GetIndexForTypeId(*void_type_id), no_args);
-        if (finalizer_proto != NULL) {
-          // We have the prototype in the dex file
-          if (klass->GetClassLoader() != NULL) {  // All non-boot finalizer methods are flagged
-            klass->SetFinalizable();
-          } else {
-            ClassHelper kh(klass.get());
-            StringPiece klass_descriptor(kh.GetDescriptorAsStringPiece());
-            // The Enum class declares a "final" finalize() method to prevent subclasses from
-            // introducing a finalizer. We don't want to set the finalizable flag for Enum or its
-            // subclasses, so we exclude it here.
-            // We also want to avoid setting the flag on Object, where we know that finalize() is
-            // empty.
-            if (klass_descriptor != "Ljava/lang/Object;" &&
-                klass_descriptor != "Ljava/lang/Enum;") {
-              klass->SetFinalizable();
-            }
-          }
-        }
-      }
-    }
-  }
   dst->SetCodeItemOffset(it.GetMethodCodeItemOffset());
-  dst->SetAccessFlags(it.GetMemberAccessFlags());
 
   dst->SetDexCacheStrings(klass->GetDexCache()->GetStrings());
   dst->SetDexCacheResolvedMethods(klass->GetDexCache()->GetResolvedMethods());
   dst->SetDexCacheResolvedTypes(klass->GetDexCache()->GetResolvedTypes());
   dst->SetDexCacheInitializedStaticStorage(klass->GetDexCache()->GetInitializedStaticStorage());
 
-  CHECK(dst->IsArtMethod());
+  uint32_t access_flags = it.GetMemberAccessFlags();
+
+  if (UNLIKELY(method_name == "finalize")) {
+    // Set finalizable flag on declaring class.
+    const DexFile::ProtoId& proto = dex_file.GetProtoId(method_id.proto_idx_);
+    if (dex_file.GetProtoParameters(proto) == NULL) {  // No arguments
+      const DexFile::TypeId& return_type = dex_file.GetTypeId(proto.return_type_idx_);
+      if (dex_file.StringDataAsStringPieceByIdx(return_type.descriptor_idx_) == "V") {
+        // Void return type.
+        if (klass->GetClassLoader() != NULL) {  // All non-boot finalizer methods are flagged
+          klass->SetFinalizable();
+        } else {
+          ClassHelper kh(klass.get());
+          StringPiece klass_descriptor(kh.GetDescriptorAsStringPiece());
+          // The Enum class declares a "final" finalize() method to prevent subclasses from
+          // introducing a finalizer. We don't want to set the finalizable flag for Enum or its
+          // subclasses, so we exclude it here.
+          // We also want to avoid setting the flag on Object, where we know that finalize() is
+          // empty.
+          if (klass_descriptor != "Ljava/lang/Object;" &&
+              klass_descriptor != "Ljava/lang/Enum;") {
+            klass->SetFinalizable();
+          }
+        }
+      }
+    }
+  } else if (method_name[0] == '<') {
+    // Fix broken access flags for initializers. Bug 11157540.
+    bool is_init = (method_name == "<init>");
+    bool is_clinit = !is_init && (method_name == "<clinit>");
+    if (UNLIKELY(!is_init && !is_clinit)) {
+      LOG(WARNING) << "Unexpected '<' at start of method name " << method_name;
+    } else {
+      if (UNLIKELY((access_flags & kAccConstructor) == 0)) {
+        LOG(WARNING) << method_name << " didn't have expected constructor access flag in class "
+            << PrettyDescriptor(klass.get()) << " in dex file " << dex_file.GetLocation();
+        access_flags |= kAccConstructor;
+      }
+    }
+  }
+  dst->SetAccessFlags(access_flags);
 
   self->EndAssertNoThreadSuspension(old_cause);
   return dst;
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index ad9347f..029b73e 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -996,7 +996,7 @@
   CHECK(dex_file != NULL);
 
   mirror::Class* klass = class_linker_->FindClass("LStaticsFromCode;", class_loader.get());
-  mirror::ArtMethod* clinit = klass->FindDirectMethod("<clinit>", "()V");
+  mirror::ArtMethod* clinit = klass->FindClassInitializer();
   mirror::ArtMethod* getS0 = klass->FindDirectMethod("getS0", "()Ljava/lang/Object;");
   const DexFile::StringId* string_id = dex_file->FindStringId("LStaticsFromCode;");
   ASSERT_TRUE(string_id != NULL);
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index e9e6c5a..c32a661 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -312,7 +312,7 @@
   //
   // Do not set the DexCache InitializedStaticStorage, since that implies <clinit> has finished
   // running.
-  if (klass == referring_class && MethodHelper(referrer).IsClassInitializer()) {
+  if (klass == referring_class && referrer->IsConstructor() && referrer->IsStatic()) {
     return klass;
   }
   if (!class_linker->EnsureInitialized(klass, true, true)) {
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index b16c2f7..2b0b1e1 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -500,6 +500,7 @@
     if (method->IsConstructor() && method->IsStatic()) {
       if (kIsDebugBuild) {
         MethodHelper mh(method);
+        CHECK(mh.IsClassInitializer());
         CHECK_STREQ(mh.GetName(), "<clinit>");
         CHECK_STREQ(mh.GetSignature().ToString().c_str(), "()V");
       }
diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc
index 1e610f2..4c5f90c 100644
--- a/runtime/mirror/object_test.cc
+++ b/runtime/mirror/object_test.cc
@@ -270,7 +270,7 @@
 
   Class* klass =
       class_linker_->FindClass("LStaticsFromCode;", soa.Decode<ClassLoader*>(class_loader));
-  ArtMethod* clinit = klass->FindDirectMethod("<clinit>", "()V");
+  ArtMethod* clinit = klass->FindClassInitializer();
   const DexFile::StringId* klass_string_id = dex_file->FindStringId("LStaticsFromCode;");
   ASSERT_TRUE(klass_string_id != NULL);
   const DexFile::TypeId* klass_type_id = dex_file->FindTypeId(
diff --git a/runtime/object_utils.h b/runtime/object_utils.h
index 692cecc..8062a89 100644
--- a/runtime/object_utils.h
+++ b/runtime/object_utils.h
@@ -592,7 +592,7 @@
   }
 
   bool IsClassInitializer() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return IsStatic() && GetNameAsStringPiece() == "<clinit>";
+    return method_->IsConstructor() && IsStatic();
   }
 
   size_t NumArgs() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {