diff options
author | 2022-08-02 15:26:06 +0100 | |
---|---|---|
committer | 2022-08-04 09:55:13 +0000 | |
commit | c3f4364b73a3291d3c930fbd5f52220e37cefa1d (patch) | |
tree | 9e39ba0d2a20493d06e22cfbe1e65da5441d527c | |
parent | c0398effdea1b4991287155fc1b2ea3f1e7565e0 (diff) |
Avoid creating unnecessary StackFrameInfo objects in StackWalker.getCallerClass() implementation
Bug: 240965799
Test: atest CtsLibcoreOjTestCases:test.java.lang.StackWalker
Change-Id: I5b528137e5805849b1e24d0e37c4b10fb3fc0040
-rw-r--r-- | runtime/native/java_lang_StackStreamFactory.cc | 2 | ||||
-rw-r--r-- | runtime/thread.cc | 47 |
2 files changed, 30 insertions, 19 deletions
diff --git a/runtime/native/java_lang_StackStreamFactory.cc b/runtime/native/java_lang_StackStreamFactory.cc index b4ad042a47..f876c1014b 100644 --- a/runtime/native/java_lang_StackStreamFactory.cc +++ b/runtime/native/java_lang_StackStreamFactory.cc @@ -43,7 +43,7 @@ static jint StackStreamFactory_nativeFetchStackFrameInfo(JNIEnv* env, jclass, static JNINativeMethod gMethods[] = { FAST_NATIVE_METHOD(StackStreamFactory, nativeGetStackAnchor, "()Ljava/lang/Object;"), - FAST_NATIVE_METHOD(StackStreamFactory, nativeFetchStackFrameInfo, "(JLjava/lang/Object;III[Ljava/lang/StackFrameInfo;)I"), + FAST_NATIVE_METHOD(StackStreamFactory, nativeFetchStackFrameInfo, "(JLjava/lang/Object;III[Ljava/lang/Object;)I"), }; void register_java_lang_StackStreamFactory(JNIEnv* env) { diff --git a/runtime/thread.cc b/runtime/thread.cc index 48b7b481d3..db43afe33f 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -3157,7 +3157,7 @@ jobjectArray Thread::InternalStackTraceToStackTraceElementArray( return result; } -static ObjPtr<mirror::StackFrameInfo> InitStackFrameInfo( +[[nodiscard]] static ObjPtr<mirror::StackFrameInfo> InitStackFrameInfo( const ScopedObjectAccessAlreadyRunnable& soa, ClassLinker* class_linker, Handle<mirror::StackFrameInfo> stackFrameInfo, @@ -3219,9 +3219,11 @@ static ObjPtr<mirror::StackFrameInfo> InitStackFrameInfo( return stackFrameInfo.Get(); } +constexpr jlong FILL_CLASS_REFS_ONLY = 0x2; // StackStreamFactory.FILL_CLASS_REFS_ONLY + jint Thread::InternalStackTraceToStackFrameInfoArray( const ScopedObjectAccessAlreadyRunnable& soa, - [[maybe_unused]] jlong mode, // See java.lang.StackStreamFactory for the mode flags + jlong mode, // See java.lang.StackStreamFactory for the mode flags jobject internal, jint startLevel, jint batchSize, @@ -3232,8 +3234,8 @@ jint Thread::InternalStackTraceToStackFrameInfoArray( int32_t depth = soa.Decode<mirror::Array>(internal)->GetLength() - 1; DCHECK_GE(depth, 0); - StackHandleScope<5> hs(soa.Self()); - Handle<mirror::ObjectArray<mirror::Object>> frames = + StackHandleScope<6> hs(soa.Self()); + Handle<mirror::ObjectArray<mirror::Object>> framesOrClasses = hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Object>>(output_array)); jint endBufferIndex = startBufferIndex; @@ -3242,11 +3244,14 @@ jint Thread::InternalStackTraceToStackFrameInfoArray( return endBufferIndex; } - int32_t bufferSize = frames->GetLength(); + int32_t bufferSize = framesOrClasses->GetLength(); if (startBufferIndex < 0 || startBufferIndex >= bufferSize) { return endBufferIndex; } + // The FILL_CLASS_REFS_ONLY flag is defined in AbstractStackWalker.fetchStackFrames() javadoc. + bool isClassArray = (mode & FILL_CLASS_REFS_ONLY) != 0; + Handle<mirror::ObjectArray<mirror::Object>> decoded_traces = hs.NewHandle(soa.Decode<mirror::Object>(internal)->AsObjectArray<mirror::Object>()); // Methods and dex PC trace is element 0. @@ -3260,26 +3265,32 @@ jint Thread::InternalStackTraceToStackFrameInfoArray( DCHECK(sfi_class != nullptr); MutableHandle<mirror::StackFrameInfo> frame = hs.NewHandle<mirror::StackFrameInfo>(nullptr); + MutableHandle<mirror::Class> clazz = hs.NewHandle<mirror::Class>(nullptr); for (uint32_t i = static_cast<uint32_t>(startLevel); i < static_cast<uint32_t>(depth); ++i) { if (endBufferIndex >= startBufferIndex + batchSize || endBufferIndex >= bufferSize) { break; } - // Prepare parameters for fields in StackFrameInfo ArtMethod* method = method_trace->GetElementPtrSize<ArtMethod*>(i, kRuntimePointerSize); - uint32_t dex_pc = method_trace->GetElementPtrSize<uint32_t>( - i + static_cast<uint32_t>(method_trace->GetLength()) / 2, kRuntimePointerSize); + if (isClassArray) { + clazz.Assign(method->GetDeclaringClass()); + framesOrClasses->Set(endBufferIndex, clazz.Get()); + } else { + // Prepare parameters for fields in StackFrameInfo + uint32_t dex_pc = method_trace->GetElementPtrSize<uint32_t>( + i + static_cast<uint32_t>(method_trace->GetLength()) / 2, kRuntimePointerSize); - ObjPtr<mirror::Object> frameObject = frames->Get(endBufferIndex); - // If libcore didn't allocate the object, we just stop here, but it's unlikely. - if (frameObject == nullptr || !frameObject->InstanceOf(sfi_class.Get())) { - break; - } - frame.Assign(ObjPtr<mirror::StackFrameInfo>::DownCast(frameObject)); - frame.Assign(InitStackFrameInfo(soa, class_linker, frame, method, dex_pc)); - // Break if InitStackFrameInfo fails to allocate objects or assign the fields. - if (frame == nullptr) { - break; + ObjPtr<mirror::Object> frameObject = framesOrClasses->Get(endBufferIndex); + // If libcore didn't allocate the object, we just stop here, but it's unlikely. + if (frameObject == nullptr || !frameObject->InstanceOf(sfi_class.Get())) { + break; + } + frame.Assign(ObjPtr<mirror::StackFrameInfo>::DownCast(frameObject)); + frame.Assign(InitStackFrameInfo(soa, class_linker, frame, method, dex_pc)); + // Break if InitStackFrameInfo fails to allocate objects or assign the fields. + if (frame == nullptr) { + break; + } } ++endBufferIndex; |