Propagate the read barrier option to Class::VisitNativeRoots.

Propagate the read barrier option from Object::VisitReferences to
Class::VisitNativeRoots.

This is a step toward the GC thread avoiding graying objects (and
reducing dirty pages) in the immune spaces.

Bug: 12687968

Change-Id: I29c4126a4ad4c40e63a934e62451fb3fb36aad43
diff --git a/runtime/art_field-inl.h b/runtime/art_field-inl.h
index d911497..564a857 100644
--- a/runtime/art_field-inl.h
+++ b/runtime/art_field-inl.h
@@ -33,9 +33,10 @@
 
 namespace art {
 
+template<ReadBarrierOption kReadBarrierOption>
 inline mirror::Class* ArtField::GetDeclaringClass() {
   GcRootSource gc_root_source(this);
-  mirror::Class* result = declaring_class_.Read(&gc_root_source);
+  mirror::Class* result = declaring_class_.Read<kReadBarrierOption>(&gc_root_source);
   DCHECK(result != nullptr);
   DCHECK(result->IsLoaded() || result->IsErroneous()) << result->GetStatus();
   return result;
diff --git a/runtime/art_field.h b/runtime/art_field.h
index b64b70f..aaccbf3 100644
--- a/runtime/art_field.h
+++ b/runtime/art_field.h
@@ -41,6 +41,7 @@
  public:
   ArtField();
 
+  template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   mirror::Class* GetDeclaringClass() SHARED_REQUIRES(Locks::mutator_lock_);
 
   void SetDeclaringClass(mirror::Class *new_declaring_class)
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index 7647ad6..26450c4 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -395,8 +395,9 @@
   return GetDeclaringClass()->GetDexCache();
 }
 
+template<ReadBarrierOption kReadBarrierOption>
 inline bool ArtMethod::IsProxyMethod() {
-  return GetDeclaringClass()->IsProxyClass();
+  return GetDeclaringClass<kReadBarrierOption>()->IsProxyClass();
 }
 
 inline ArtMethod* ArtMethod::GetInterfaceMethodIfProxy(size_t pointer_size) {
@@ -438,24 +439,24 @@
   return type;
 }
 
-template<typename RootVisitorType>
+template<ReadBarrierOption kReadBarrierOption, typename RootVisitorType>
 void ArtMethod::VisitRoots(RootVisitorType& visitor, size_t pointer_size) {
-  ArtMethod* interface_method = nullptr;
-  mirror::Class* klass = declaring_class_.Read();
-  if (LIKELY(klass != nullptr)) {
+  if (LIKELY(!declaring_class_.IsNull())) {
+    visitor.VisitRoot(declaring_class_.AddressWithoutBarrier());
+    mirror::Class* klass = declaring_class_.Read<kReadBarrierOption>();
     if (UNLIKELY(klass->IsProxyClass())) {
       // For normal methods, dex cache shortcuts will be visited through the declaring class.
       // However, for proxies we need to keep the interface method alive, so we visit its roots.
-      interface_method = mirror::DexCache::GetElementPtrSize(
+      ArtMethod* interface_method = mirror::DexCache::GetElementPtrSize(
           GetDexCacheResolvedMethods(pointer_size),
           GetDexMethodIndex(),
           pointer_size);
       DCHECK(interface_method != nullptr);
       DCHECK_EQ(interface_method,
-                Runtime::Current()->GetClassLinker()->FindMethodForProxy(klass, this));
+                Runtime::Current()->GetClassLinker()->FindMethodForProxy<kReadBarrierOption>(
+                    klass, this));
       interface_method->VisitRoots(visitor, pointer_size);
     }
-    visitor.VisitRoot(declaring_class_.AddressWithoutBarrier());
     // We know we don't have profiling information if the class hasn't been verified. Note
     // that this check also ensures the IsNative call can be made, as IsNative expects a fully
     // created class (and not a retired one).
@@ -463,7 +464,7 @@
       // Runtime methods and native methods use the same field as the profiling info for
       // storing their own data (jni entrypoint for native methods, and ImtConflictTable for
       // some runtime methods).
-      if (!IsNative() && !IsRuntimeMethod()) {
+      if (!IsNative<kReadBarrierOption>() && !IsRuntimeMethod()) {
         ProfilingInfo* profiling_info = GetProfilingInfo(pointer_size);
         if (profiling_info != nullptr) {
           profiling_info->VisitRoots(visitor);
diff --git a/runtime/art_method.h b/runtime/art_method.h
index a012a5a..2b025f8 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -340,6 +340,7 @@
     return (GetAccessFlags() & kAccSynthetic) != 0;
   }
 
+  template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   bool IsProxyMethod() SHARED_REQUIRES(Locks::mutator_lock_);
 
   bool SkipAccessChecks() {
@@ -564,7 +565,7 @@
       SHARED_REQUIRES(Locks::mutator_lock_);
 
   // NO_THREAD_SAFETY_ANALYSIS since we don't know what the callback requires.
-  template<typename RootVisitorType>
+  template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier, typename RootVisitorType>
   void VisitRoots(RootVisitorType& visitor, size_t pointer_size) NO_THREAD_SAFETY_ANALYSIS;
 
   const DexFile* GetDexFile() SHARED_REQUIRES(Locks::mutator_lock_);
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index f3e260b..f2575f7 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -225,6 +225,34 @@
   return klass;
 }
 
+template<ReadBarrierOption kReadBarrierOption>
+ArtMethod* ClassLinker::FindMethodForProxy(mirror::Class* proxy_class, ArtMethod* proxy_method) {
+  DCHECK(proxy_class->IsProxyClass());
+  DCHECK(proxy_method->IsProxyMethod<kReadBarrierOption>());
+  {
+    Thread* const self = Thread::Current();
+    ReaderMutexLock mu(self, dex_lock_);
+    // Locate the dex cache of the original interface/Object
+    for (const DexCacheData& data : dex_caches_) {
+      if (!self->IsJWeakCleared(data.weak_root) &&
+          proxy_method->HasSameDexCacheResolvedTypes(data.resolved_types,
+                                                     image_pointer_size_)) {
+        mirror::DexCache* dex_cache = down_cast<mirror::DexCache*>(
+            self->DecodeJObject(data.weak_root));
+        if (dex_cache != nullptr) {
+          ArtMethod* resolved_method = dex_cache->GetResolvedMethod(
+              proxy_method->GetDexMethodIndex(), image_pointer_size_);
+          CHECK(resolved_method != nullptr);
+          return resolved_method;
+        }
+      }
+    }
+  }
+  LOG(FATAL) << "Didn't find dex cache for " << PrettyClass(proxy_class) << " "
+      << PrettyMethod(proxy_method);
+  UNREACHABLE();
+}
+
 }  // namespace art
 
 #endif  // ART_RUNTIME_CLASS_LINKER_INL_H_
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index d03b57c..343bc8f 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -4248,33 +4248,6 @@
   return DotToDescriptor(name->ToModifiedUtf8().c_str());
 }
 
-ArtMethod* ClassLinker::FindMethodForProxy(mirror::Class* proxy_class, ArtMethod* proxy_method) {
-  DCHECK(proxy_class->IsProxyClass());
-  DCHECK(proxy_method->IsProxyMethod());
-  {
-    Thread* const self = Thread::Current();
-    ReaderMutexLock mu(self, dex_lock_);
-    // Locate the dex cache of the original interface/Object
-    for (const DexCacheData& data : dex_caches_) {
-      if (!self->IsJWeakCleared(data.weak_root) &&
-          proxy_method->HasSameDexCacheResolvedTypes(data.resolved_types,
-                                                     image_pointer_size_)) {
-        mirror::DexCache* dex_cache = down_cast<mirror::DexCache*>(
-            self->DecodeJObject(data.weak_root));
-        if (dex_cache != nullptr) {
-          ArtMethod* resolved_method = dex_cache->GetResolvedMethod(
-              proxy_method->GetDexMethodIndex(), image_pointer_size_);
-          CHECK(resolved_method != nullptr);
-          return resolved_method;
-        }
-      }
-    }
-  }
-  LOG(FATAL) << "Didn't find dex cache for " << PrettyClass(proxy_class) << " "
-      << PrettyMethod(proxy_method);
-  UNREACHABLE();
-}
-
 void ClassLinker::CreateProxyConstructor(Handle<mirror::Class> klass, ArtMethod* out) {
   // Create constructor for Proxy that must initialize the method.
   CHECK_EQ(GetClassRoot(kJavaLangReflectProxy)->NumDirectMethods(), 18u);
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index f6ce545..3cf0fb6 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -482,6 +482,7 @@
       SHARED_REQUIRES(Locks::mutator_lock_);
   std::string GetDescriptorForProxy(mirror::Class* proxy_class)
       SHARED_REQUIRES(Locks::mutator_lock_);
+  template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   ArtMethod* FindMethodForProxy(mirror::Class* proxy_class, ArtMethod* proxy_method)
       REQUIRES(!dex_lock_)
       SHARED_REQUIRES(Locks::mutator_lock_);
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index dfb728f..f8436c3 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -534,7 +534,7 @@
 inline MemberOffset Class::GetFirstReferenceInstanceFieldOffset() {
   Class* super_class = GetSuperClass<kVerifyFlags, kReadBarrierOption>();
   return (super_class != nullptr)
-      ? MemberOffset(RoundUp(super_class->GetObjectSize(),
+      ? MemberOffset(RoundUp(super_class->GetObjectSize<kVerifyFlags, kReadBarrierOption>(),
                              sizeof(mirror::HeapReference<mirror::Object>)))
       : ClassOffset();
 }
@@ -780,7 +780,8 @@
   }
   if (kVisitNativeRoots) {
     // Since this class is reachable, we must also visit the associated roots when we scan it.
-    VisitNativeRoots(visitor, Runtime::Current()->GetClassLinker()->GetImagePointerSize());
+    VisitNativeRoots<kReadBarrierOption>(
+        visitor, Runtime::Current()->GetClassLinker()->GetImagePointerSize());
   }
 }
 
@@ -919,24 +920,24 @@
   return GetFieldPtr<GcRoot<String>*>(DexCacheStringsOffset());
 }
 
-template<class Visitor>
+template<ReadBarrierOption kReadBarrierOption, class Visitor>
 void mirror::Class::VisitNativeRoots(Visitor& visitor, size_t pointer_size) {
   for (ArtField& field : GetSFieldsUnchecked()) {
     // Visit roots first in case the declaring class gets moved.
     field.VisitRoots(visitor);
     if (kIsDebugBuild && IsResolved()) {
-      CHECK_EQ(field.GetDeclaringClass(), this) << GetStatus();
+      CHECK_EQ(field.GetDeclaringClass<kReadBarrierOption>(), this) << GetStatus();
     }
   }
   for (ArtField& field : GetIFieldsUnchecked()) {
     // Visit roots first in case the declaring class gets moved.
     field.VisitRoots(visitor);
     if (kIsDebugBuild && IsResolved()) {
-      CHECK_EQ(field.GetDeclaringClass(), this) << GetStatus();
+      CHECK_EQ(field.GetDeclaringClass<kReadBarrierOption>(), this) << GetStatus();
     }
   }
   for (ArtMethod& method : GetMethods(pointer_size)) {
-    method.VisitRoots(visitor, pointer_size);
+    method.VisitRoots<kReadBarrierOption>(visitor, pointer_size);
   }
 }
 
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 8c20fa6..5235a3e 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -1156,7 +1156,7 @@
 
   // Visit native roots visits roots which are keyed off the native pointers such as ArtFields and
   // ArtMethods.
-  template<class Visitor>
+  template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier, class Visitor>
   void VisitNativeRoots(Visitor& visitor, size_t pointer_size)
       SHARED_REQUIRES(Locks::mutator_lock_);