Home | History | Annotate | Download | only in openjdkjvmti
      1 /* Copyright (C) 2016 The Android Open Source Project
      2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      3  *
      4  * This file implements interfaces from the file jvmti.h. This implementation
      5  * is licensed under the same terms as the file jvmti.h.  The
      6  * copyright and license information for the file jvmti.h follows.
      7  *
      8  * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
      9  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     10  *
     11  * This code is free software; you can redistribute it and/or modify it
     12  * under the terms of the GNU General Public License version 2 only, as
     13  * published by the Free Software Foundation.  Oracle designates this
     14  * particular file as subject to the "Classpath" exception as provided
     15  * by Oracle in the LICENSE file that accompanied this code.
     16  *
     17  * This code is distributed in the hope that it will be useful, but WITHOUT
     18  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     19  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     20  * version 2 for more details (a copy is included in the LICENSE file that
     21  * accompanied this code).
     22  *
     23  * You should have received a copy of the GNU General Public License version
     24  * 2 along with this work; if not, write to the Free Software Foundation,
     25  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     26  *
     27  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     28  * or visit www.oracle.com if you need additional information or have any
     29  * questions.
     30  */
     31 
     32 #include "ti_stack.h"
     33 
     34 #include <algorithm>
     35 #include <list>
     36 #include <unordered_map>
     37 #include <vector>
     38 
     39 #include "art_field-inl.h"
     40 #include "art_method-inl.h"
     41 #include "art_jvmti.h"
     42 #include "base/bit_utils.h"
     43 #include "base/enums.h"
     44 #include "base/mutex.h"
     45 #include "dex_file.h"
     46 #include "dex_file_annotations.h"
     47 #include "handle_scope-inl.h"
     48 #include "jni_env_ext.h"
     49 #include "jni_internal.h"
     50 #include "mirror/class.h"
     51 #include "mirror/dex_cache.h"
     52 #include "scoped_thread_state_change-inl.h"
     53 #include "ScopedLocalRef.h"
     54 #include "stack.h"
     55 #include "thread-inl.h"
     56 #include "thread_list.h"
     57 #include "thread_pool.h"
     58 #include "well_known_classes.h"
     59 
     60 namespace openjdkjvmti {
     61 
     62 struct GetStackTraceVisitor : public art::StackVisitor {
     63   GetStackTraceVisitor(art::Thread* thread_in,
     64                        size_t start_,
     65                        size_t stop_)
     66       : StackVisitor(thread_in, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
     67         start(start_),
     68         stop(stop_) {}
     69 
     70   bool VisitFrame() REQUIRES_SHARED(art::Locks::mutator_lock_) {
     71     art::ArtMethod* m = GetMethod();
     72     if (m->IsRuntimeMethod()) {
     73       return true;
     74     }
     75 
     76     if (start == 0) {
     77       m = m->GetInterfaceMethodIfProxy(art::kRuntimePointerSize);
     78       jmethodID id = art::jni::EncodeArtMethod(m);
     79 
     80       uint32_t dex_pc = GetDexPc(false);
     81       jlong dex_location = (dex_pc == art::DexFile::kDexNoIndex) ? -1 : static_cast<jlong>(dex_pc);
     82 
     83       jvmtiFrameInfo info = { id, dex_location };
     84       frames.push_back(info);
     85 
     86       if (stop == 1) {
     87         return false;  // We're done.
     88       } else if (stop > 0) {
     89         stop--;
     90       }
     91     } else {
     92       start--;
     93     }
     94 
     95     return true;
     96   }
     97 
     98   std::vector<jvmtiFrameInfo> frames;
     99   size_t start;
    100   size_t stop;
    101 };
    102 
    103 struct GetStackTraceClosure : public art::Closure {
    104  public:
    105   GetStackTraceClosure(size_t start, size_t stop)
    106       : start_input(start),
    107         stop_input(stop),
    108         start_result(0),
    109         stop_result(0) {}
    110 
    111   void Run(art::Thread* self) OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
    112     GetStackTraceVisitor visitor(self, start_input, stop_input);
    113     visitor.WalkStack(false);
    114 
    115     frames.swap(visitor.frames);
    116     start_result = visitor.start;
    117     stop_result = visitor.stop;
    118   }
    119 
    120   const size_t start_input;
    121   const size_t stop_input;
    122 
    123   std::vector<jvmtiFrameInfo> frames;
    124   size_t start_result;
    125   size_t stop_result;
    126 };
    127 
    128 static jvmtiError TranslateFrameVector(const std::vector<jvmtiFrameInfo>& frames,
    129                                        jint start_depth,
    130                                        size_t start_result,
    131                                        jint max_frame_count,
    132                                        jvmtiFrameInfo* frame_buffer,
    133                                        jint* count_ptr) {
    134   size_t collected_frames = frames.size();
    135 
    136   // Assume we're here having collected something.
    137   DCHECK_GT(max_frame_count, 0);
    138 
    139   // Frames from the top.
    140   if (start_depth >= 0) {
    141     if (start_result != 0) {
    142       // Not enough frames.
    143       return ERR(ILLEGAL_ARGUMENT);
    144     }
    145     DCHECK_LE(collected_frames, static_cast<size_t>(max_frame_count));
    146     if (frames.size() > 0) {
    147       memcpy(frame_buffer, frames.data(), collected_frames * sizeof(jvmtiFrameInfo));
    148     }
    149     *count_ptr = static_cast<jint>(frames.size());
    150     return ERR(NONE);
    151   }
    152 
    153   // Frames from the bottom.
    154   if (collected_frames < static_cast<size_t>(-start_depth)) {
    155     return ERR(ILLEGAL_ARGUMENT);
    156   }
    157 
    158   size_t count = std::min(static_cast<size_t>(-start_depth), static_cast<size_t>(max_frame_count));
    159   memcpy(frame_buffer,
    160          &frames.data()[collected_frames + start_depth],
    161          count * sizeof(jvmtiFrameInfo));
    162   *count_ptr = static_cast<jint>(count);
    163   return ERR(NONE);
    164 }
    165 
    166 static jvmtiError GetThread(JNIEnv* env, jthread java_thread, art::Thread** thread) {
    167   if (java_thread == nullptr) {
    168     *thread = art::Thread::Current();
    169     if (*thread == nullptr) {
    170       // GetStackTrace can only be run during the live phase, so the current thread should be
    171       // attached and thus available. Getting a null for current means we're starting up or
    172       // dying.
    173       return ERR(WRONG_PHASE);
    174     }
    175   } else {
    176     if (!env->IsInstanceOf(java_thread, art::WellKnownClasses::java_lang_Thread)) {
    177       return ERR(INVALID_THREAD);
    178     }
    179 
    180     // TODO: Need non-aborting call here, to return JVMTI_ERROR_INVALID_THREAD.
    181     art::ScopedObjectAccess soa(art::Thread::Current());
    182     art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_);
    183     *thread = art::Thread::FromManagedThread(soa, java_thread);
    184     if (*thread == nullptr) {
    185       return ERR(THREAD_NOT_ALIVE);
    186     }
    187   }
    188   return ERR(NONE);
    189 }
    190 
    191 jvmtiError StackUtil::GetStackTrace(jvmtiEnv* jvmti_env ATTRIBUTE_UNUSED,
    192                                     jthread java_thread,
    193                                     jint start_depth,
    194                                     jint max_frame_count,
    195                                     jvmtiFrameInfo* frame_buffer,
    196                                     jint* count_ptr) {
    197   art::Thread* thread;
    198   jvmtiError thread_error = GetThread(art::Thread::Current()->GetJniEnv(), java_thread, &thread);
    199   if (thread_error != ERR(NONE)) {
    200     return thread_error;
    201   }
    202   DCHECK(thread != nullptr);
    203 
    204   art::ThreadState state = thread->GetState();
    205   if (state == art::ThreadState::kStarting ||
    206       state == art::ThreadState::kTerminated ||
    207       thread->IsStillStarting()) {
    208     return ERR(THREAD_NOT_ALIVE);
    209   }
    210 
    211   if (max_frame_count < 0) {
    212     return ERR(ILLEGAL_ARGUMENT);
    213   }
    214   if (frame_buffer == nullptr || count_ptr == nullptr) {
    215     return ERR(NULL_POINTER);
    216   }
    217 
    218   if (max_frame_count == 0) {
    219     *count_ptr = 0;
    220     return ERR(NONE);
    221   }
    222 
    223   GetStackTraceClosure closure(start_depth >= 0 ? static_cast<size_t>(start_depth) : 0,
    224                                start_depth >= 0 ? static_cast<size_t>(max_frame_count) : 0);
    225   thread->RequestSynchronousCheckpoint(&closure);
    226 
    227   return TranslateFrameVector(closure.frames,
    228                               start_depth,
    229                               closure.start_result,
    230                               max_frame_count,
    231                               frame_buffer,
    232                               count_ptr);
    233 }
    234 
    235 struct GetAllStackTraceClosure : public art::Closure {
    236  public:
    237   explicit GetAllStackTraceClosure(size_t stop)
    238       : start_input(0),
    239         stop_input(stop),
    240         frames_lock("GetAllStackTraceGuard", art::LockLevel::kAbortLock),
    241         start_result(0),
    242         stop_result(0) {}
    243 
    244   void Run(art::Thread* self)
    245       OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) REQUIRES(!frames_lock) {
    246     // self should be live here (so it could be suspended). No need to filter.
    247 
    248     art::Thread* current = art::Thread::Current();
    249     std::vector<jvmtiFrameInfo> self_frames;
    250 
    251     GetStackTraceVisitor visitor(self, start_input, stop_input);
    252     visitor.WalkStack(false);
    253 
    254     self_frames.swap(visitor.frames);
    255 
    256     art::MutexLock mu(current, frames_lock);
    257     frames.emplace(self, self_frames);
    258   }
    259 
    260   const size_t start_input;
    261   const size_t stop_input;
    262 
    263   art::Mutex frames_lock;
    264   std::unordered_map<art::Thread*, std::vector<jvmtiFrameInfo>> frames GUARDED_BY(frames_lock);
    265   size_t start_result;
    266   size_t stop_result;
    267 };
    268 
    269 
    270 
    271 jvmtiError StackUtil::GetAllStackTraces(jvmtiEnv* env,
    272                                         jint max_frame_count,
    273                                         jvmtiStackInfo** stack_info_ptr,
    274                                         jint* thread_count_ptr) {
    275   if (max_frame_count < 0) {
    276     return ERR(ILLEGAL_ARGUMENT);
    277   }
    278   if (stack_info_ptr == nullptr || thread_count_ptr == nullptr) {
    279     return ERR(NULL_POINTER);
    280   }
    281 
    282 
    283   art::Thread* current = art::Thread::Current();
    284   art::ScopedObjectAccess soa(current);      // Now we know we have the shared lock.
    285   art::ScopedThreadSuspension sts(current, art::kWaitingForDebuggerSuspension);
    286   art::ScopedSuspendAll ssa("GetAllStackTraces");
    287 
    288   std::vector<art::Thread*> threads;
    289   std::vector<std::vector<jvmtiFrameInfo>> frames;
    290   {
    291     std::list<art::Thread*> thread_list;
    292     {
    293       art::MutexLock mu(current, *art::Locks::thread_list_lock_);
    294       thread_list = art::Runtime::Current()->GetThreadList()->GetList();
    295     }
    296 
    297     for (art::Thread* thread : thread_list) {
    298       // Skip threads that are still starting.
    299       if (thread->IsStillStarting()) {
    300         continue;
    301       }
    302 
    303       GetStackTraceClosure closure(0u, static_cast<size_t>(max_frame_count));
    304       thread->RequestSynchronousCheckpoint(&closure);
    305 
    306       threads.push_back(thread);
    307       frames.emplace_back();
    308       frames.back().swap(closure.frames);
    309     }
    310   }
    311 
    312   // Convert the data into our output format. Note: we need to keep the threads suspended,
    313   // as we need to access them for their peers.
    314 
    315   // Note: we use an array of jvmtiStackInfo for convenience. The spec says we need to
    316   //       allocate one big chunk for this and the actual frames, which means we need
    317   //       to either be conservative or rearrange things later (the latter is implemented).
    318   std::unique_ptr<jvmtiStackInfo[]> stack_info_array(new jvmtiStackInfo[frames.size()]);
    319   std::vector<std::unique_ptr<jvmtiFrameInfo[]>> frame_infos;
    320   frame_infos.reserve(frames.size());
    321 
    322   // Now run through and add data for each thread.
    323   size_t sum_frames = 0;
    324   for (size_t index = 0; index < frames.size(); ++index) {
    325     jvmtiStackInfo& stack_info = stack_info_array.get()[index];
    326     memset(&stack_info, 0, sizeof(jvmtiStackInfo));
    327 
    328     art::Thread* self = threads[index];
    329     const std::vector<jvmtiFrameInfo>& thread_frames = frames[index];
    330 
    331     // For the time being, set the thread to null. We don't have good ScopedLocalRef
    332     // infrastructure.
    333     DCHECK(self->GetPeerFromOtherThread() != nullptr);
    334     stack_info.thread = nullptr;
    335     stack_info.state = JVMTI_THREAD_STATE_SUSPENDED;
    336 
    337     size_t collected_frames = thread_frames.size();
    338     if (max_frame_count == 0 || collected_frames == 0) {
    339       stack_info.frame_count = 0;
    340       stack_info.frame_buffer = nullptr;
    341       continue;
    342     }
    343     DCHECK_LE(collected_frames, static_cast<size_t>(max_frame_count));
    344 
    345     jvmtiFrameInfo* frame_info = new jvmtiFrameInfo[collected_frames];
    346     frame_infos.emplace_back(frame_info);
    347 
    348     jint count;
    349     jvmtiError translate_result = TranslateFrameVector(thread_frames,
    350                                                        0,
    351                                                        0,
    352                                                        static_cast<jint>(collected_frames),
    353                                                        frame_info,
    354                                                        &count);
    355     DCHECK(translate_result == JVMTI_ERROR_NONE);
    356     stack_info.frame_count = static_cast<jint>(collected_frames);
    357     stack_info.frame_buffer = frame_info;
    358     sum_frames += static_cast<size_t>(count);
    359   }
    360 
    361   // No errors, yet. Now put it all into an output buffer.
    362   size_t rounded_stack_info_size = art::RoundUp(sizeof(jvmtiStackInfo) * frames.size(),
    363                                                 alignof(jvmtiFrameInfo));
    364   size_t chunk_size = rounded_stack_info_size + sum_frames * sizeof(jvmtiFrameInfo);
    365   unsigned char* chunk_data;
    366   jvmtiError alloc_result = env->Allocate(chunk_size, &chunk_data);
    367   if (alloc_result != ERR(NONE)) {
    368     return alloc_result;
    369   }
    370 
    371   jvmtiStackInfo* stack_info = reinterpret_cast<jvmtiStackInfo*>(chunk_data);
    372   // First copy in all the basic data.
    373   memcpy(stack_info, stack_info_array.get(), sizeof(jvmtiStackInfo) * frames.size());
    374 
    375   // Now copy the frames and fix up the pointers.
    376   jvmtiFrameInfo* frame_info = reinterpret_cast<jvmtiFrameInfo*>(
    377       chunk_data + rounded_stack_info_size);
    378   for (size_t i = 0; i < frames.size(); ++i) {
    379     jvmtiStackInfo& old_stack_info = stack_info_array.get()[i];
    380     jvmtiStackInfo& new_stack_info = stack_info[i];
    381 
    382     jthread thread_peer = current->GetJniEnv()->AddLocalReference<jthread>(
    383         threads[i]->GetPeerFromOtherThread());
    384     new_stack_info.thread = thread_peer;
    385 
    386     if (old_stack_info.frame_count > 0) {
    387       // Only copy when there's data - leave the nullptr alone.
    388       size_t frames_size = static_cast<size_t>(old_stack_info.frame_count) * sizeof(jvmtiFrameInfo);
    389       memcpy(frame_info, old_stack_info.frame_buffer, frames_size);
    390       new_stack_info.frame_buffer = frame_info;
    391       frame_info += old_stack_info.frame_count;
    392     }
    393   }
    394 
    395   *stack_info_ptr = stack_info;
    396   *thread_count_ptr = static_cast<jint>(frames.size());
    397 
    398   return ERR(NONE);
    399 }
    400 
    401 jvmtiError StackUtil::GetThreadListStackTraces(jvmtiEnv* env,
    402                                                jint thread_count,
    403                                                const jthread* thread_list,
    404                                                jint max_frame_count,
    405                                                jvmtiStackInfo** stack_info_ptr) {
    406   if (max_frame_count < 0) {
    407     return ERR(ILLEGAL_ARGUMENT);
    408   }
    409   if (thread_count < 0) {
    410     return ERR(ILLEGAL_ARGUMENT);
    411   }
    412   if (thread_count == 0) {
    413     *stack_info_ptr = nullptr;
    414     return ERR(NONE);
    415   }
    416   if (stack_info_ptr == nullptr || stack_info_ptr == nullptr) {
    417     return ERR(NULL_POINTER);
    418   }
    419 
    420   art::Thread* current = art::Thread::Current();
    421   art::ScopedObjectAccess soa(current);      // Now we know we have the shared lock.
    422 
    423   // Decode all threads to raw pointers. Put them into a handle scope to avoid any moving GC bugs.
    424   art::VariableSizedHandleScope hs(current);
    425   std::vector<art::Handle<art::mirror::Object>> handles;
    426   for (jint i = 0; i != thread_count; ++i) {
    427     if (thread_list[i] == nullptr) {
    428       return ERR(INVALID_THREAD);
    429     }
    430     if (!soa.Env()->IsInstanceOf(thread_list[i], art::WellKnownClasses::java_lang_Thread)) {
    431       return ERR(INVALID_THREAD);
    432     }
    433     handles.push_back(hs.NewHandle(soa.Decode<art::mirror::Object>(thread_list[i])));
    434   }
    435 
    436   std::vector<art::Thread*> threads;
    437   std::vector<size_t> thread_list_indices;
    438   std::vector<std::vector<jvmtiFrameInfo>> frames;
    439 
    440   {
    441     art::ScopedThreadSuspension sts(current, art::kWaitingForDebuggerSuspension);
    442     art::ScopedSuspendAll ssa("GetThreadListStackTraces");
    443 
    444     {
    445       std::list<art::Thread*> art_thread_list;
    446       {
    447         art::MutexLock mu(current, *art::Locks::thread_list_lock_);
    448         art_thread_list = art::Runtime::Current()->GetThreadList()->GetList();
    449       }
    450 
    451       for (art::Thread* thread : art_thread_list) {
    452         if (thread->IsStillStarting()) {
    453           // Skip this. We can't get the jpeer, and if it is for a thread in the thread_list,
    454           // we'll just report STARTING.
    455           continue;
    456         }
    457 
    458         // Get the peer, and check whether we know it.
    459         art::ObjPtr<art::mirror::Object> peer = thread->GetPeerFromOtherThread();
    460         for (size_t index = 0; index != handles.size(); ++index) {
    461           if (peer == handles[index].Get()) {
    462             // Found the thread.
    463             GetStackTraceClosure closure(0u, static_cast<size_t>(max_frame_count));
    464             thread->RequestSynchronousCheckpoint(&closure);
    465 
    466             threads.push_back(thread);
    467             thread_list_indices.push_back(index);
    468             frames.emplace_back();
    469             frames.back().swap(closure.frames);
    470 
    471             continue;
    472           }
    473         }
    474 
    475         // Must be not started, or dead. We'll deal with it at the end.
    476       }
    477     }
    478   }
    479 
    480   // Convert the data into our output format.
    481 
    482   // Note: we use an array of jvmtiStackInfo for convenience. The spec says we need to
    483   //       allocate one big chunk for this and the actual frames, which means we need
    484   //       to either be conservative or rearrange things later (the latter is implemented).
    485   std::unique_ptr<jvmtiStackInfo[]> stack_info_array(new jvmtiStackInfo[frames.size()]);
    486   std::vector<std::unique_ptr<jvmtiFrameInfo[]>> frame_infos;
    487   frame_infos.reserve(frames.size());
    488 
    489   // Now run through and add data for each thread.
    490   size_t sum_frames = 0;
    491   for (size_t index = 0; index < frames.size(); ++index) {
    492     jvmtiStackInfo& stack_info = stack_info_array.get()[index];
    493     memset(&stack_info, 0, sizeof(jvmtiStackInfo));
    494 
    495     art::Thread* self = threads[index];
    496     const std::vector<jvmtiFrameInfo>& thread_frames = frames[index];
    497 
    498     // For the time being, set the thread to null. We don't have good ScopedLocalRef
    499     // infrastructure.
    500     DCHECK(self->GetPeerFromOtherThread() != nullptr);
    501     stack_info.thread = nullptr;
    502     stack_info.state = JVMTI_THREAD_STATE_SUSPENDED;
    503 
    504     size_t collected_frames = thread_frames.size();
    505     if (max_frame_count == 0 || collected_frames == 0) {
    506       stack_info.frame_count = 0;
    507       stack_info.frame_buffer = nullptr;
    508       continue;
    509     }
    510     DCHECK_LE(collected_frames, static_cast<size_t>(max_frame_count));
    511 
    512     jvmtiFrameInfo* frame_info = new jvmtiFrameInfo[collected_frames];
    513     frame_infos.emplace_back(frame_info);
    514 
    515     jint count;
    516     jvmtiError translate_result = TranslateFrameVector(thread_frames,
    517                                                        0,
    518                                                        0,
    519                                                        static_cast<jint>(collected_frames),
    520                                                        frame_info,
    521                                                        &count);
    522     DCHECK(translate_result == JVMTI_ERROR_NONE);
    523     stack_info.frame_count = static_cast<jint>(collected_frames);
    524     stack_info.frame_buffer = frame_info;
    525     sum_frames += static_cast<size_t>(count);
    526   }
    527 
    528   // No errors, yet. Now put it all into an output buffer. Note that this is not frames.size(),
    529   // potentially.
    530   size_t rounded_stack_info_size = art::RoundUp(sizeof(jvmtiStackInfo) * thread_count,
    531                                                 alignof(jvmtiFrameInfo));
    532   size_t chunk_size = rounded_stack_info_size + sum_frames * sizeof(jvmtiFrameInfo);
    533   unsigned char* chunk_data;
    534   jvmtiError alloc_result = env->Allocate(chunk_size, &chunk_data);
    535   if (alloc_result != ERR(NONE)) {
    536     return alloc_result;
    537   }
    538 
    539   jvmtiStackInfo* stack_info = reinterpret_cast<jvmtiStackInfo*>(chunk_data);
    540   jvmtiFrameInfo* frame_info = reinterpret_cast<jvmtiFrameInfo*>(
    541       chunk_data + rounded_stack_info_size);
    542 
    543   for (size_t i = 0; i < static_cast<size_t>(thread_count); ++i) {
    544     // Check whether we found a running thread for this.
    545     // Note: For simplicity, and with the expectation that the list is usually small, use a simple
    546     //       search. (The list is *not* sorted!)
    547     auto it = std::find(thread_list_indices.begin(), thread_list_indices.end(), i);
    548     if (it == thread_list_indices.end()) {
    549       // No native thread. Must be new or dead. We need to fill out the stack info now.
    550       // (Need to read the Java "started" field to know whether this is starting or terminated.)
    551       art::ObjPtr<art::mirror::Object> peer = soa.Decode<art::mirror::Object>(thread_list[i]);
    552       art::ObjPtr<art::mirror::Class> klass = peer->GetClass();
    553       art::ArtField* started_field = klass->FindDeclaredInstanceField("started", "Z");
    554       CHECK(started_field != nullptr);
    555       bool started = started_field->GetBoolean(peer) != 0;
    556       constexpr jint kStartedState = JVMTI_JAVA_LANG_THREAD_STATE_NEW;
    557       constexpr jint kTerminatedState = JVMTI_THREAD_STATE_TERMINATED |
    558           JVMTI_JAVA_LANG_THREAD_STATE_TERMINATED;
    559       stack_info[i].thread = reinterpret_cast<JNIEnv*>(soa.Env())->NewLocalRef(thread_list[i]);
    560       stack_info[i].state = started ? kTerminatedState : kStartedState;
    561       stack_info[i].frame_count = 0;
    562       stack_info[i].frame_buffer = nullptr;
    563     } else {
    564       // Had a native thread and frames.
    565       size_t f_index = it - thread_list_indices.begin();
    566 
    567       jvmtiStackInfo& old_stack_info = stack_info_array.get()[f_index];
    568       jvmtiStackInfo& new_stack_info = stack_info[i];
    569 
    570       memcpy(&new_stack_info, &old_stack_info, sizeof(jvmtiStackInfo));
    571       new_stack_info.thread = reinterpret_cast<JNIEnv*>(soa.Env())->NewLocalRef(thread_list[i]);
    572       if (old_stack_info.frame_count > 0) {
    573         // Only copy when there's data - leave the nullptr alone.
    574         size_t frames_size =
    575             static_cast<size_t>(old_stack_info.frame_count) * sizeof(jvmtiFrameInfo);
    576         memcpy(frame_info, old_stack_info.frame_buffer, frames_size);
    577         new_stack_info.frame_buffer = frame_info;
    578         frame_info += old_stack_info.frame_count;
    579       }
    580     }
    581   }
    582 
    583   * stack_info_ptr = stack_info;
    584 
    585   return ERR(NONE);
    586 }
    587 
    588 // Walks up the stack counting Java frames. This is not StackVisitor::ComputeNumFrames, as
    589 // runtime methods and transitions must not be counted.
    590 struct GetFrameCountVisitor : public art::StackVisitor {
    591   explicit GetFrameCountVisitor(art::Thread* thread)
    592       : art::StackVisitor(thread, nullptr, art::StackVisitor::StackWalkKind::kIncludeInlinedFrames),
    593         count(0) {}
    594 
    595   bool VisitFrame() REQUIRES_SHARED(art::Locks::mutator_lock_) {
    596     art::ArtMethod* m = GetMethod();
    597     const bool do_count = !(m == nullptr || m->IsRuntimeMethod());
    598     if (do_count) {
    599       count++;
    600     }
    601     return true;
    602   }
    603 
    604   size_t count;
    605 };
    606 
    607 struct GetFrameCountClosure : public art::Closure {
    608  public:
    609   GetFrameCountClosure() : count(0) {}
    610 
    611   void Run(art::Thread* self) OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
    612     GetFrameCountVisitor visitor(self);
    613     visitor.WalkStack(false);
    614 
    615     count = visitor.count;
    616   }
    617 
    618   size_t count;
    619 };
    620 
    621 jvmtiError StackUtil::GetFrameCount(jvmtiEnv* env ATTRIBUTE_UNUSED,
    622                                     jthread java_thread,
    623                                     jint* count_ptr) {
    624   art::Thread* thread;
    625   jvmtiError thread_error = GetThread(art::Thread::Current()->GetJniEnv(), java_thread, &thread);
    626   if (thread_error != ERR(NONE)) {
    627     return thread_error;
    628   }
    629   DCHECK(thread != nullptr);
    630 
    631   if (count_ptr == nullptr) {
    632     return ERR(NULL_POINTER);
    633   }
    634 
    635   GetFrameCountClosure closure;
    636   thread->RequestSynchronousCheckpoint(&closure);
    637 
    638   *count_ptr = closure.count;
    639   return ERR(NONE);
    640 }
    641 
    642 // Walks up the stack 'n' callers, when used with Thread::WalkStack.
    643 struct GetLocationVisitor : public art::StackVisitor {
    644   GetLocationVisitor(art::Thread* thread, size_t n_in)
    645       : art::StackVisitor(thread, nullptr, art::StackVisitor::StackWalkKind::kIncludeInlinedFrames),
    646         n(n_in),
    647         count(0),
    648         caller(nullptr),
    649         caller_dex_pc(0) {}
    650 
    651   bool VisitFrame() REQUIRES_SHARED(art::Locks::mutator_lock_) {
    652     art::ArtMethod* m = GetMethod();
    653     const bool do_count = !(m == nullptr || m->IsRuntimeMethod());
    654     if (do_count) {
    655       DCHECK(caller == nullptr);
    656       if (count == n) {
    657         caller = m;
    658         caller_dex_pc = GetDexPc(false);
    659         return false;
    660       }
    661       count++;
    662     }
    663     return true;
    664   }
    665 
    666   const size_t n;
    667   size_t count;
    668   art::ArtMethod* caller;
    669   uint32_t caller_dex_pc;
    670 };
    671 
    672 struct GetLocationClosure : public art::Closure {
    673  public:
    674   explicit GetLocationClosure(size_t n_in) : n(n_in), method(nullptr), dex_pc(0) {}
    675 
    676   void Run(art::Thread* self) OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
    677     GetLocationVisitor visitor(self, n);
    678     visitor.WalkStack(false);
    679 
    680     method = visitor.caller;
    681     dex_pc = visitor.caller_dex_pc;
    682   }
    683 
    684   const size_t n;
    685   art::ArtMethod* method;
    686   uint32_t dex_pc;
    687 };
    688 
    689 jvmtiError StackUtil::GetFrameLocation(jvmtiEnv* env ATTRIBUTE_UNUSED,
    690                                        jthread java_thread,
    691                                        jint depth,
    692                                        jmethodID* method_ptr,
    693                                        jlocation* location_ptr) {
    694   art::Thread* thread;
    695   jvmtiError thread_error = GetThread(art::Thread::Current()->GetJniEnv(), java_thread, &thread);
    696   if (thread_error != ERR(NONE)) {
    697     return thread_error;
    698   }
    699   DCHECK(thread != nullptr);
    700 
    701   if (depth < 0) {
    702     return ERR(ILLEGAL_ARGUMENT);
    703   }
    704   if (method_ptr == nullptr || location_ptr == nullptr) {
    705     return ERR(NULL_POINTER);
    706   }
    707 
    708   GetLocationClosure closure(static_cast<size_t>(depth));
    709   thread->RequestSynchronousCheckpoint(&closure);
    710 
    711   if (closure.method == nullptr) {
    712     return ERR(NO_MORE_FRAMES);
    713   }
    714 
    715   *method_ptr = art::jni::EncodeArtMethod(closure.method);
    716   if (closure.method->IsNative()) {
    717     *location_ptr = -1;
    718   } else {
    719     if (closure.dex_pc == art::DexFile::kDexNoIndex) {
    720       return ERR(INTERNAL);
    721     }
    722     *location_ptr = static_cast<jlocation>(closure.dex_pc);
    723   }
    724 
    725   return ERR(NONE);
    726 }
    727 
    728 }  // namespace openjdkjvmti
    729