ART: Correctly make methods preverified

Bug: 16828525
Change-Id: I66756348b2aa50e41dacca59769b6810a91c73b0
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 9d67b8c..f2c6af5 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -3415,6 +3415,7 @@
   // Don't attempt to re-verify if already sufficiently verified.
   if (klass->IsVerified() ||
       (klass->IsCompileTimeVerified() && Runtime::Current()->IsCompiler())) {
+    EnsurePreverifiedMethods(klass);
     return;
   }
 
@@ -3437,6 +3438,7 @@
   // Skip verification if disabled.
   if (!Runtime::Current()->IsVerificationEnabled()) {
     klass->SetStatus(mirror::Class::kStatusVerified, self);
+    EnsurePreverifiedMethods(klass);
     return;
   }
 
@@ -3539,7 +3541,14 @@
     // Note: we're going here during compilation and at runtime. When we set the
     // kAccPreverified flag when compiling image classes, the flag is recorded
     // in the image and is set when loading the image.
+    EnsurePreverifiedMethods(klass);
+  }
+}
+
+void ClassLinker::EnsurePreverifiedMethods(Handle<mirror::Class> klass) {
+  if ((klass->GetAccessFlags() & kAccPreverified) == 0) {
     klass->SetPreverifiedFlagOnAllMethods();
+    klass->SetAccessFlags(klass->GetAccessFlags() | kAccPreverified);
   }
 }
 
@@ -3677,7 +3686,8 @@
   }
   DCHECK(klass->GetClass() != NULL);
   klass->SetObjectSize(sizeof(mirror::Proxy));
-  klass->SetAccessFlags(kAccClassIsProxy | kAccPublic | kAccFinal);
+  // Set the class access flags incl. preverified, so we do not try to set the flag on the methods.
+  klass->SetAccessFlags(kAccClassIsProxy | kAccPublic | kAccFinal | kAccPreverified);
   klass->SetClassLoader(soa.Decode<mirror::ClassLoader*>(loader));
   DCHECK_EQ(klass->GetPrimitiveType(), Primitive::kPrimNot);
   klass->SetName(soa.Decode<mirror::String*>(name));
@@ -4238,6 +4248,7 @@
                                     bool can_init_parents) {
   DCHECK(c.Get() != nullptr);
   if (c->IsInitialized()) {
+    EnsurePreverifiedMethods(c);
     return true;
   }
   const bool success = InitializeClass(c, can_init_fields, can_init_parents);
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 79cbb02..aef0866 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -626,6 +626,11 @@
                                        Handle<mirror::ArtMethod> prototype)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  // Ensures that methods have the kAccPreverified bit set. We use the kAccPreverfied bit on the
+  // class access flags to determine whether this has been done before.
+  void EnsurePreverifiedMethods(Handle<mirror::Class> c)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   mirror::Class* LookupClassFromTableLocked(const char* descriptor,
                                             const mirror::ClassLoader* class_loader,
                                             size_t hash)
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 69c281e..883c6e2 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -1092,4 +1092,65 @@
   EXPECT_EQ(c->GetClassSize(), mirror::ArtMethod::ClassSize());
 }
 
+static void CheckMethod(mirror::ArtMethod* method, bool verified)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  if (!method->IsNative() && !method->IsAbstract()) {
+    EXPECT_EQ((method->GetAccessFlags() & kAccPreverified) != 0U, verified)
+        << PrettyMethod(method, true);
+  }
+}
+
+static void CheckPreverified(mirror::Class* c, bool preverified)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  EXPECT_EQ((c->GetAccessFlags() & kAccPreverified) != 0U, preverified)
+      << "Class " << PrettyClass(c) << " not as expected";
+  for (uint32_t i = 0; i < c->NumDirectMethods(); ++i) {
+    CheckMethod(c->GetDirectMethod(i), preverified);
+  }
+  for (uint32_t i = 0; i < c->NumVirtualMethods(); ++i) {
+    CheckMethod(c->GetVirtualMethod(i), preverified);
+  }
+}
+
+TEST_F(ClassLinkerTest, Preverified_InitializedBoot) {
+  ScopedObjectAccess soa(Thread::Current());
+
+  mirror::Class* JavaLangObject = class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;");
+  ASSERT_TRUE(JavaLangObject != NULL);
+  EXPECT_TRUE(JavaLangObject->IsInitialized()) << "Not testing already initialized class from the "
+                                                  "core";
+  CheckPreverified(JavaLangObject, true);
+}
+
+TEST_F(ClassLinkerTest, Preverified_UninitializedBoot) {
+  ScopedObjectAccess soa(Thread::Current());
+
+  StackHandleScope<1> hs(soa.Self());
+
+  Handle<mirror::Class> security_manager(hs.NewHandle(class_linker_->FindSystemClass(
+      soa.Self(), "Ljava/lang/SecurityManager;")));
+  EXPECT_FALSE(security_manager->IsInitialized()) << "Not testing uninitialized class from the "
+                                                     "core";
+
+  CheckPreverified(security_manager.Get(), false);
+
+  class_linker_->EnsureInitialized(security_manager, true, true);
+  CheckPreverified(security_manager.Get(), true);
+}
+
+TEST_F(ClassLinkerTest, Preverified_App) {
+  ScopedObjectAccess soa(Thread::Current());
+
+  StackHandleScope<2> hs(soa.Self());
+  Handle<mirror::ClassLoader> class_loader(
+      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Statics"))));
+  Handle<mirror::Class> statics(
+      hs.NewHandle(class_linker_->FindClass(soa.Self(), "LStatics;", class_loader)));
+
+  CheckPreverified(statics.Get(), false);
+
+  class_linker_->EnsureInitialized(statics, true, true);
+  CheckPreverified(statics.Get(), true);
+}
+
 }  // namespace art
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index b0ff7ea..8e44471 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -724,6 +724,15 @@
   klass->SetDexTypeIndex(DexFile::kDexNoIndex16);  // Default to no valid type index.
 }
 
+inline void Class::SetAccessFlags(uint32_t new_access_flags) {
+  // Called inside a transaction when setting pre-verified flag during boot image compilation.
+  if (Runtime::Current()->IsActiveTransaction()) {
+    SetField32<true>(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), new_access_flags);
+  } else {
+    SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), new_access_flags);
+  }
+}
+
 }  // namespace mirror
 }  // namespace art
 
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 13d0c80..43ac98d 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -217,10 +217,7 @@
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   uint32_t GetAccessFlags() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void SetAccessFlags(uint32_t new_access_flags) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    // Not called within a transaction.
-    SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), new_access_flags);
-  }
+  void SetAccessFlags(uint32_t new_access_flags) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Returns true if the class is an interface.
   bool IsInterface() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
diff --git a/runtime/modifiers.h b/runtime/modifiers.h
index e599b03..2814ed8 100644
--- a/runtime/modifiers.h
+++ b/runtime/modifiers.h
@@ -45,7 +45,7 @@
 static const uint32_t kAccConstructor = 0x00010000;  // method (dex only) <init> and <clinit>
 static const uint32_t kAccDeclaredSynchronized = 0x00020000;  // method (dex only)
 static const uint32_t kAccClassIsProxy = 0x00040000;  // class (dex only)
-static const uint32_t kAccPreverified = 0x00080000;  // method (dex only)
+static const uint32_t kAccPreverified = 0x00080000;  // class (runtime), method (dex only)
 static const uint32_t kAccFastNative = 0x0080000;  // method (dex only)
 static const uint32_t kAccPortableCompiled = 0x0100000;  // method (dex only)