diff options
| -rw-r--r-- | runtime/art_method-inl.h | 9 | ||||
| -rw-r--r-- | runtime/art_method.h | 3 | ||||
| -rw-r--r-- | runtime/thread.cc | 20 | ||||
| -rw-r--r-- | test/004-ThreadStress/src/Main.java | 3 |
4 files changed, 33 insertions, 2 deletions
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h index bb3c72c433..51398cad35 100644 --- a/runtime/art_method-inl.h +++ b/runtime/art_method-inl.h @@ -63,6 +63,15 @@ inline void ArtMethod::SetDeclaringClass(mirror::Class* new_declaring_class) { 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 90352b7c08..85c03ed5e7 100644 --- a/runtime/art_method.h +++ b/runtime/art_method.h @@ -67,6 +67,9 @@ class ArtMethod FINAL { 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 d54a7a6aa8..a33e150b93 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -2419,6 +2419,7 @@ class ReferenceMapVisitor : public StackVisitor { 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 @@ class ReferenceMapVisitor : public StackVisitor { } 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()) { diff --git a/test/004-ThreadStress/src/Main.java b/test/004-ThreadStress/src/Main.java index 1db7cc8385..7acd950e68 100644 --- a/test/004-ThreadStress/src/Main.java +++ b/test/004-ThreadStress/src/Main.java @@ -546,6 +546,9 @@ public class Main implements Runnable { operation.perform(); i = (i + 1) % operations.length; } + } catch (OutOfMemoryError e) { + // Catch OutOfMemoryErrors since these can cause the test to fail it they print + // the stack trace after "Finishing worker". } finally { if (DEBUG) { System.out.println("Finishing ThreadStress Daemon for " + id); |