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()) {