Visit declaring class of methods on call stack

Bug: 22720414
Change-Id: Iab9727dde243d76fd9dfdb1db73899fedd1ab6ea
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index bb3c72c..51398ca 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -63,6 +63,15 @@
   declaring_class_ = GcRoot<mirror::Class>(new_declaring_class);
 }
 
+inline bool ArtMethod::CASDeclaringClass(mirror::Class* expected_class,
+                                         mirror::Class* desired_class) {
+  GcRoot<mirror::Class> expected_root(expected_class);
+  GcRoot<mirror::Class> desired_root(desired_class);
+  return reinterpret_cast<Atomic<GcRoot<mirror::Class>>*>(&declaring_class_)->
+      CompareExchangeStrongSequentiallyConsistent(
+          expected_root, desired_root);
+}
+
 inline uint32_t ArtMethod::GetAccessFlags() {
   DCHECK(IsRuntimeMethod() || GetDeclaringClass()->IsIdxLoaded() ||
          GetDeclaringClass()->IsErroneous());
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 90352b7..85c03ed 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -67,6 +67,9 @@
   void SetDeclaringClass(mirror::Class *new_declaring_class)
       SHARED_REQUIRES(Locks::mutator_lock_);
 
+  bool CASDeclaringClass(mirror::Class* expected_class, mirror::Class* desired_class)
+      SHARED_REQUIRES(Locks::mutator_lock_);
+
   static MemberOffset DeclaringClassOffset() {
     return MemberOffset(OFFSETOF_MEMBER(ArtMethod, declaring_class_));
   }
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 74e3f11..37860ad 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -2419,6 +2419,7 @@
 
   void VisitShadowFrame(ShadowFrame* shadow_frame) SHARED_REQUIRES(Locks::mutator_lock_) {
     ArtMethod* m = shadow_frame->GetMethod();
+    VisitDeclaringClass(m);
     DCHECK(m != nullptr);
     size_t num_regs = shadow_frame->NumberOfVRegs();
     if (m->IsNative() || shadow_frame->HasReferenceArray()) {
@@ -2459,10 +2460,25 @@
   }
 
  private:
+  // Visiting the declaring class is necessary so that we don't unload the class of a method that
+  // is executing. We need to ensure that the code stays mapped.
+  void VisitDeclaringClass(ArtMethod* method) SHARED_REQUIRES(Locks::mutator_lock_) {
+    mirror::Class* klass = method->GetDeclaringClassNoBarrier();
+    // klass can be null for runtime methods.
+    if (klass != nullptr) {
+      mirror::Object* new_ref = klass;
+      visitor_(&new_ref, -1, this);
+      if (new_ref != klass) {
+        method->CASDeclaringClass(klass, new_ref->AsClass());
+      }
+    }
+  }
+
   void VisitQuickFrame() SHARED_REQUIRES(Locks::mutator_lock_) {
-    auto* cur_quick_frame = GetCurrentQuickFrame();
+    ArtMethod** cur_quick_frame = GetCurrentQuickFrame();
     DCHECK(cur_quick_frame != nullptr);
-    auto* m = *cur_quick_frame;
+    ArtMethod* m = *cur_quick_frame;
+    VisitDeclaringClass(m);
 
     // Process register map (which native and runtime methods don't have)
     if (!m->IsNative() && !m->IsRuntimeMethod() && !m->IsProxyMethod()) {