diff options
Diffstat (limited to 'runtime/thread.cc')
-rw-r--r-- | runtime/thread.cc | 27 |
1 files changed, 20 insertions, 7 deletions
diff --git a/runtime/thread.cc b/runtime/thread.cc index 78f9174886..ff0a020b0c 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -2980,9 +2980,19 @@ class BuildInternalStackTraceVisitor : public StackVisitor { methods_and_pcs->SetElementPtrSize</*kTransactionActive=*/ false, /*kCheckTransaction=*/ false>( static_cast<uint32_t>(methods_and_pcs->GetLength()) / 2 + count_, dex_pc, pointer_size_); // Save the declaring class of the method to ensure that the declaring classes of the methods - // do not get unloaded while the stack trace is live. + // do not get unloaded while the stack trace is live. However, this does not work for copied + // methods because the declaring class of a copied method points to an interface class which + // may be in a different class loader. Instead, retrieve the class loader associated with the + // allocator that holds the copied method. This is much cheaper than finding the actual class. + ObjPtr<mirror::Object> keep_alive; + if (UNLIKELY(method->IsCopied())) { + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + keep_alive = class_linker->GetHoldingClassLoaderOfCopiedMethod(self_, method); + } else { + keep_alive = method->GetDeclaringClass(); + } trace_->Set</*kTransactionActive=*/ false, /*kCheckTransaction=*/ false>( - static_cast<int32_t>(count_) + 1, method->GetDeclaringClass()); + static_cast<int32_t>(count_) + 1, keep_alive); ++count_; } @@ -3000,11 +3010,14 @@ class BuildInternalStackTraceVisitor : public StackVisitor { uint32_t skip_depth_; // Current position down stack trace. uint32_t count_ = 0; - // An object array where the first element is a pointer array that contains the ArtMethod - // pointers on the stack and dex PCs. The rest of the elements are the declaring class of - // the ArtMethod pointers. trace_[i+1] contains the declaring class of the ArtMethod of the - // i'th frame. We're initializing a newly allocated trace, so we do not need to record that - // under a transaction. If the transaction is aborted, the whole trace shall be unreachable. + // An object array where the first element is a pointer array that contains the `ArtMethod` + // pointers on the stack and dex PCs. The rest of the elements are referencing objects + // that shall keep the methods alive, namely the declaring class of the `ArtMethod` for + // declared methods and the class loader for copied methods (because it's faster to find + // the class loader than the actual class that holds the copied method). The `trace_[i+1]` + // contains the declaring class or class loader of the `ArtMethod` of the i'th frame. + // We're initializing a newly allocated trace, so we do not need to record that under + // a transaction. If the transaction is aborted, the whole trace shall be unreachable. mirror::ObjectArray<mirror::Object>* trace_ = nullptr; // For cross compilation. const PointerSize pointer_size_; |