From f10dfcdb76b02d68537d44753bd00f78f89c2d3e Mon Sep 17 00:00:00 2001 From: Andreas Gampe Date: Fri, 2 Dec 2016 14:42:33 -0800 Subject: [PATCH] ART: Stack locals Add reporting of stack-locals roots. Use the new precise root visiting to get dalvik register information for compiled frames. Bug: 31385354 Test: m test-art-host-run-test-913-heaps Change-Id: Ieb86f67829e546692c30faa08eb44e8dcf2b2c6a --- runtime/openjdkjvmti/ti_heap.cc | 36 ++++++++++++++++++++++++++++++- test/913-heaps/expected.txt | 8 ++++--- test/913-heaps/heaps.cc | 47 ++++++++++++++++++++++++++++++++++++----- 3 files changed, 82 insertions(+), 9 deletions(-) diff --git a/runtime/openjdkjvmti/ti_heap.cc b/runtime/openjdkjvmti/ti_heap.cc index 894cec252..7b2521d63 100644 --- a/runtime/openjdkjvmti/ti_heap.cc +++ b/runtime/openjdkjvmti/ti_heap.cc @@ -190,7 +190,12 @@ class FollowReferencesHelper FINAL { REQUIRES(!*tag_table_->GetAllowDisallowLock()) { if (initial_object_.IsNull()) { CollectAndReportRootsVisitor carrv(this, tag_table_, &worklist_, &visited_); - art::Runtime::Current()->VisitRoots(&carrv); + + // We need precise info (e.g., vregs). + constexpr art::VisitRootFlags kRootFlags = static_cast( + art::VisitRootFlags::kVisitRootFlagAllRoots | art::VisitRootFlags::kVisitRootFlagPrecise); + art::Runtime::Current()->VisitRoots(&carrv, kRootFlags); + art::Runtime::Current()->VisitImageRoots(&carrv); stop_reports_ = carrv.IsStopReports(); @@ -322,7 +327,36 @@ class FollowReferencesHelper FINAL { } case art::RootType::kRootJavaFrame: + { + uint32_t thread_id = info.GetThreadId(); + ref_info->stack_local.thread_id = thread_id; + + art::Thread* thread = FindThread(info); + if (thread != nullptr) { + art::mirror::Object* thread_obj = thread->GetPeer(); + if (thread->IsStillStarting()) { + thread_obj = nullptr; + } else { + thread_obj = thread->GetPeer(); + } + if (thread_obj != nullptr) { + ref_info->stack_local.thread_tag = tag_table_->GetTagOrZero(thread_obj); + } + } + + auto& java_info = static_cast(info); + ref_info->stack_local.slot = static_cast(java_info.GetVReg()); + const art::StackVisitor* visitor = java_info.GetVisitor(); + ref_info->stack_local.location = + static_cast(visitor->GetDexPc(false /* abort_on_failure */)); + ref_info->stack_local.depth = static_cast(visitor->GetFrameDepth()); + art::ArtMethod* method = visitor->GetMethod(); + if (method != nullptr) { + ref_info->stack_local.method = art::jni::EncodeArtMethod(method); + } + return JVMTI_HEAP_REFERENCE_STACK_LOCAL; + } case art::RootType::kRootNativeStack: case art::RootType::kRootThreadBlock: diff --git a/test/913-heaps/expected.txt b/test/913-heaps/expected.txt index aba2a9a71..e5fa53f20 100644 --- a/test/913-heaps/expected.txt +++ b/test/913-heaps/expected.txt @@ -1,7 +1,7 @@ --- true true -root@root --(stack-local)--> 1@1000 [size=16, length=-1] -root@root --(stack-local)--> 3000@0 [size=132, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=11,location= 31])--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=132, length=-1] root@root --(thread)--> 3000@0 [size=132, length=-1] 0@0 --(array-element@0)--> 1@1000 [size=16, length=-1] 1001@0 --(superclass)--> 1000@0 [size=123, length=-1] @@ -40,7 +40,9 @@ root@root --(thread)--> 3000@0 [size=132, length=-1] --- root@root --(jni-global)--> 1@1000 [size=16, length=-1] root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1] -root@root --(stack-local)--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=10,location= 6])--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 6])--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=3,location= 18])--> 1@1000 [size=16, length=-1] root@root --(thread)--> 1@1000 [size=16, length=-1] root@root --(thread)--> 3000@0 [size=132, length=-1] 1001@0 --(superclass)--> 1000@0 [size=123, length=-1] diff --git a/test/913-heaps/heaps.cc b/test/913-heaps/heaps.cc index 340671da1..7b00fcdcc 100644 --- a/test/913-heaps/heaps.cc +++ b/test/913-heaps/heaps.cc @@ -269,6 +269,43 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_followReferences(JNIEnv* env jvmtiHeapReferenceInfo info_; }; + class StackLocalElement : public Elem { + public: + StackLocalElement(const std::string& referrer, + const std::string& referree, + jlong size, + jint length, + const jvmtiHeapReferenceInfo* reference_info) + : Elem(referrer, referree, size, length) { + memcpy(&info_, reference_info, sizeof(jvmtiHeapReferenceInfo)); + } + + protected: + std::string PrintArrowType() const OVERRIDE { + char* name = nullptr; + if (info_.stack_local.method != nullptr) { + jvmti_env->GetMethodName(info_.stack_local.method, &name, nullptr, nullptr); + } + std::string ret = StringPrintf("stack-local[id=%" PRId64 ",tag=%" PRId64 ",depth=%d," + "method=%s,vreg=%d,location=% " PRId64 "]", + info_.stack_local.thread_id, + info_.stack_local.thread_tag, + info_.stack_local.depth, + name == nullptr ? "" : name, + info_.stack_local.slot, + info_.stack_local.location); + if (name != nullptr) { + jvmti_env->Deallocate(reinterpret_cast(name)); + } + + return ret; + } + + private: + const std::string string_; + jvmtiHeapReferenceInfo info_; + }; + // For simple or unimplemented cases. class StringElement : public Elem { public: @@ -380,11 +417,11 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_followReferences(JNIEnv* env length, "monitor")); case JVMTI_HEAP_REFERENCE_STACK_LOCAL: - return std::unique_ptr(new StringElement(referrer, - referree, - size, - length, - "stack-local")); + return std::unique_ptr(new StackLocalElement(referrer, + referree, + size, + length, + reference_info)); case JVMTI_HEAP_REFERENCE_JNI_LOCAL: return std::unique_ptr(new JNILocalElement(referrer, referree, -- 2.11.0