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_method.h"
     33 
     34 #include <type_traits>
     35 
     36 #include "art_jvmti.h"
     37 #include "art_method-inl.h"
     38 #include "base/enums.h"
     39 #include "base/mutex-inl.h"
     40 #include "dex/code_item_accessors-inl.h"
     41 #include "dex/dex_file_annotations.h"
     42 #include "dex/dex_file_types.h"
     43 #include "dex/modifiers.h"
     44 #include "events-inl.h"
     45 #include "gc_root-inl.h"
     46 #include "jit/jit.h"
     47 #include "jni_internal.h"
     48 #include "mirror/class-inl.h"
     49 #include "mirror/class_loader.h"
     50 #include "mirror/object-inl.h"
     51 #include "mirror/object_array-inl.h"
     52 #include "nativehelper/scoped_local_ref.h"
     53 #include "oat_file.h"
     54 #include "runtime_callbacks.h"
     55 #include "scoped_thread_state_change-inl.h"
     56 #include "stack.h"
     57 #include "thread-current-inl.h"
     58 #include "thread_list.h"
     59 #include "ti_stack.h"
     60 #include "ti_thread.h"
     61 #include "ti_phase.h"
     62 
     63 namespace openjdkjvmti {
     64 
     65 struct TiMethodCallback : public art::MethodCallback {
     66   void RegisterNativeMethod(art::ArtMethod* method,
     67                             const void* cur_method,
     68                             /*out*/void** new_method)
     69       OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
     70     if (event_handler->IsEventEnabledAnywhere(ArtJvmtiEvent::kNativeMethodBind)) {
     71       art::Thread* thread = art::Thread::Current();
     72       art::JNIEnvExt* jnienv = thread->GetJniEnv();
     73       ScopedLocalRef<jthread> thread_jni(
     74           jnienv, PhaseUtil::IsLivePhase() ? jnienv->AddLocalReference<jthread>(thread->GetPeer())
     75                                            : nullptr);
     76       art::ScopedThreadSuspension sts(thread, art::ThreadState::kNative);
     77       event_handler->DispatchEvent<ArtJvmtiEvent::kNativeMethodBind>(
     78           thread,
     79           static_cast<JNIEnv*>(jnienv),
     80           thread_jni.get(),
     81           art::jni::EncodeArtMethod(method),
     82           const_cast<void*>(cur_method),
     83           new_method);
     84     }
     85   }
     86 
     87   EventHandler* event_handler = nullptr;
     88 };
     89 
     90 TiMethodCallback gMethodCallback;
     91 
     92 void MethodUtil::Register(EventHandler* handler) {
     93   gMethodCallback.event_handler = handler;
     94   art::ScopedThreadStateChange stsc(art::Thread::Current(),
     95                                     art::ThreadState::kWaitingForDebuggerToAttach);
     96   art::ScopedSuspendAll ssa("Add method callback");
     97   art::RuntimeCallbacks* callbacks = art::Runtime::Current()->GetRuntimeCallbacks();
     98   callbacks->AddMethodCallback(&gMethodCallback);
     99 }
    100 
    101 void MethodUtil::Unregister() {
    102   art::ScopedThreadStateChange stsc(art::Thread::Current(),
    103                                     art::ThreadState::kWaitingForDebuggerToAttach);
    104   art::ScopedSuspendAll ssa("Remove method callback");
    105   art::RuntimeCallbacks* callbacks = art::Runtime::Current()->GetRuntimeCallbacks();
    106   callbacks->RemoveMethodCallback(&gMethodCallback);
    107 }
    108 
    109 jvmtiError MethodUtil::GetBytecodes(jvmtiEnv* env,
    110                                     jmethodID method,
    111                                     jint* size_ptr,
    112                                     unsigned char** bytecode_ptr) {
    113   if (method == nullptr) {
    114     return ERR(INVALID_METHODID);
    115   }
    116   art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
    117 
    118   if (art_method->IsNative()) {
    119     return ERR(NATIVE_METHOD);
    120   }
    121 
    122   if (size_ptr == nullptr || bytecode_ptr == nullptr) {
    123     return ERR(NULL_POINTER);
    124   }
    125 
    126   art::ScopedObjectAccess soa(art::Thread::Current());
    127   art::CodeItemInstructionAccessor accessor(art_method->DexInstructions());
    128   if (!accessor.HasCodeItem()) {
    129     *size_ptr = 0;
    130     *bytecode_ptr = nullptr;
    131     return OK;
    132   }
    133   // 2 bytes per instruction for dex code.
    134   *size_ptr = accessor.InsnsSizeInCodeUnits() * 2;
    135   jvmtiError err = env->Allocate(*size_ptr, bytecode_ptr);
    136   if (err != OK) {
    137     return err;
    138   }
    139   memcpy(*bytecode_ptr, accessor.Insns(), *size_ptr);
    140   return OK;
    141 }
    142 
    143 jvmtiError MethodUtil::GetArgumentsSize(jvmtiEnv* env ATTRIBUTE_UNUSED,
    144                                         jmethodID method,
    145                                         jint* size_ptr) {
    146   if (method == nullptr) {
    147     return ERR(INVALID_METHODID);
    148   }
    149   art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
    150 
    151   if (art_method->IsNative()) {
    152     return ERR(NATIVE_METHOD);
    153   }
    154 
    155   if (size_ptr == nullptr) {
    156     return ERR(NULL_POINTER);
    157   }
    158 
    159   art::ScopedObjectAccess soa(art::Thread::Current());
    160   if (art_method->IsProxyMethod() || art_method->IsAbstract()) {
    161     // Use the shorty.
    162     art::ArtMethod* base_method = art_method->GetInterfaceMethodIfProxy(art::kRuntimePointerSize);
    163     size_t arg_count = art::ArtMethod::NumArgRegisters(base_method->GetShorty());
    164     if (!base_method->IsStatic()) {
    165       arg_count++;
    166     }
    167     *size_ptr = static_cast<jint>(arg_count);
    168     return ERR(NONE);
    169   }
    170 
    171   DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
    172   *size_ptr = art_method->DexInstructionData().InsSize();
    173 
    174   return ERR(NONE);
    175 }
    176 
    177 jvmtiError MethodUtil::GetLocalVariableTable(jvmtiEnv* env,
    178                                              jmethodID method,
    179                                              jint* entry_count_ptr,
    180                                              jvmtiLocalVariableEntry** table_ptr) {
    181   if (method == nullptr) {
    182     return ERR(INVALID_METHODID);
    183   }
    184   art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
    185 
    186   if (art_method->IsNative()) {
    187     return ERR(NATIVE_METHOD);
    188   }
    189 
    190   if (entry_count_ptr == nullptr || table_ptr == nullptr) {
    191     return ERR(NULL_POINTER);
    192   }
    193 
    194   art::ScopedObjectAccess soa(art::Thread::Current());
    195 
    196   const art::DexFile* const dex_file = art_method->GetDexFile();
    197   if (dex_file == nullptr) {
    198     return ERR(ABSENT_INFORMATION);
    199   }
    200 
    201   // TODO HasCodeItem == false means that the method is abstract (or native, but we check that
    202   // earlier). We should check what is returned by the RI in this situation since it's not clear
    203   // what the appropriate return value is from the spec.
    204   art::CodeItemDebugInfoAccessor accessor(art_method->DexInstructionDebugInfo());
    205   if (!accessor.HasCodeItem()) {
    206     return ERR(ABSENT_INFORMATION);
    207   }
    208 
    209   struct LocalVariableContext {
    210     explicit LocalVariableContext(jvmtiEnv* jenv) : env_(jenv), variables_(), err_(OK) {}
    211 
    212     static void Callback(void* raw_ctx, const art::DexFile::LocalInfo& entry) {
    213       reinterpret_cast<LocalVariableContext*>(raw_ctx)->Insert(entry);
    214     }
    215 
    216     void Insert(const art::DexFile::LocalInfo& entry) {
    217       if (err_ != OK) {
    218         return;
    219       }
    220       JvmtiUniquePtr<char[]> name_str = CopyString(env_, entry.name_, &err_);
    221       if (err_ != OK) {
    222         return;
    223       }
    224       JvmtiUniquePtr<char[]> sig_str = CopyString(env_, entry.descriptor_, &err_);
    225       if (err_ != OK) {
    226         return;
    227       }
    228       JvmtiUniquePtr<char[]> generic_sig_str = CopyString(env_, entry.signature_, &err_);
    229       if (err_ != OK) {
    230         return;
    231       }
    232       variables_.push_back({
    233         .start_location = static_cast<jlocation>(entry.start_address_),
    234         .length = static_cast<jint>(entry.end_address_ - entry.start_address_),
    235         .name = name_str.release(),
    236         .signature = sig_str.release(),
    237         .generic_signature = generic_sig_str.release(),
    238         .slot = entry.reg_,
    239       });
    240     }
    241 
    242     jvmtiError Release(jint* out_entry_count_ptr, jvmtiLocalVariableEntry** out_table_ptr) {
    243       jlong table_size = sizeof(jvmtiLocalVariableEntry) * variables_.size();
    244       if (err_ != OK ||
    245           (err_ = env_->Allocate(table_size,
    246                                  reinterpret_cast<unsigned char**>(out_table_ptr))) != OK) {
    247         Cleanup();
    248         return err_;
    249       } else {
    250         *out_entry_count_ptr = variables_.size();
    251         memcpy(*out_table_ptr, variables_.data(), table_size);
    252         return OK;
    253       }
    254     }
    255 
    256     void Cleanup() {
    257       for (jvmtiLocalVariableEntry& e : variables_) {
    258         env_->Deallocate(reinterpret_cast<unsigned char*>(e.name));
    259         env_->Deallocate(reinterpret_cast<unsigned char*>(e.signature));
    260         env_->Deallocate(reinterpret_cast<unsigned char*>(e.generic_signature));
    261       }
    262     }
    263 
    264     jvmtiEnv* env_;
    265     std::vector<jvmtiLocalVariableEntry> variables_;
    266     jvmtiError err_;
    267   };
    268 
    269   LocalVariableContext context(env);
    270   if (!accessor.DecodeDebugLocalInfo(art_method->IsStatic(),
    271                                      art_method->GetDexMethodIndex(),
    272                                      LocalVariableContext::Callback,
    273                                      &context)) {
    274     // Something went wrong with decoding the debug information. It might as well not be there.
    275     return ERR(ABSENT_INFORMATION);
    276   } else {
    277     return context.Release(entry_count_ptr, table_ptr);
    278   }
    279 }
    280 
    281 jvmtiError MethodUtil::GetMaxLocals(jvmtiEnv* env ATTRIBUTE_UNUSED,
    282                                     jmethodID method,
    283                                     jint* max_ptr) {
    284   if (method == nullptr) {
    285     return ERR(INVALID_METHODID);
    286   }
    287   art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
    288 
    289   if (art_method->IsNative()) {
    290     return ERR(NATIVE_METHOD);
    291   }
    292 
    293   if (max_ptr == nullptr) {
    294     return ERR(NULL_POINTER);
    295   }
    296 
    297   art::ScopedObjectAccess soa(art::Thread::Current());
    298   if (art_method->IsProxyMethod() || art_method->IsAbstract()) {
    299     // This isn't specified as an error case, so return 0.
    300     *max_ptr = 0;
    301     return ERR(NONE);
    302   }
    303 
    304   DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
    305   *max_ptr = art_method->DexInstructionData().RegistersSize();
    306 
    307   return ERR(NONE);
    308 }
    309 
    310 jvmtiError MethodUtil::GetMethodName(jvmtiEnv* env,
    311                                      jmethodID method,
    312                                      char** name_ptr,
    313                                      char** signature_ptr,
    314                                      char** generic_ptr) {
    315   art::ScopedObjectAccess soa(art::Thread::Current());
    316   art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
    317   art_method = art_method->GetInterfaceMethodIfProxy(art::kRuntimePointerSize);
    318 
    319   JvmtiUniquePtr<char[]> name_copy;
    320   if (name_ptr != nullptr) {
    321     const char* method_name = art_method->GetName();
    322     if (method_name == nullptr) {
    323       method_name = "<error>";
    324     }
    325     jvmtiError ret;
    326     name_copy = CopyString(env, method_name, &ret);
    327     if (name_copy == nullptr) {
    328       return ret;
    329     }
    330     *name_ptr = name_copy.get();
    331   }
    332 
    333   JvmtiUniquePtr<char[]> signature_copy;
    334   if (signature_ptr != nullptr) {
    335     const art::Signature sig = art_method->GetSignature();
    336     std::string str = sig.ToString();
    337     jvmtiError ret;
    338     signature_copy = CopyString(env, str.c_str(), &ret);
    339     if (signature_copy == nullptr) {
    340       return ret;
    341     }
    342     *signature_ptr = signature_copy.get();
    343   }
    344 
    345   if (generic_ptr != nullptr) {
    346     *generic_ptr = nullptr;
    347     if (!art_method->GetDeclaringClass()->IsProxyClass()) {
    348       art::mirror::ObjectArray<art::mirror::String>* str_array =
    349           art::annotations::GetSignatureAnnotationForMethod(art_method);
    350       if (str_array != nullptr) {
    351         std::ostringstream oss;
    352         for (int32_t i = 0; i != str_array->GetLength(); ++i) {
    353           oss << str_array->Get(i)->ToModifiedUtf8();
    354         }
    355         std::string output_string = oss.str();
    356         jvmtiError ret;
    357         JvmtiUniquePtr<char[]> generic_copy = CopyString(env, output_string.c_str(), &ret);
    358         if (generic_copy == nullptr) {
    359           return ret;
    360         }
    361         *generic_ptr = generic_copy.release();
    362       } else if (soa.Self()->IsExceptionPending()) {
    363         // TODO: Should we report an error here?
    364         soa.Self()->ClearException();
    365       }
    366     }
    367   }
    368 
    369   // Everything is fine, release the buffers.
    370   name_copy.release();
    371   signature_copy.release();
    372 
    373   return ERR(NONE);
    374 }
    375 
    376 jvmtiError MethodUtil::GetMethodDeclaringClass(jvmtiEnv* env ATTRIBUTE_UNUSED,
    377                                                jmethodID method,
    378                                                jclass* declaring_class_ptr) {
    379   if (declaring_class_ptr == nullptr) {
    380     return ERR(NULL_POINTER);
    381   }
    382 
    383   art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
    384   // Note: No GetInterfaceMethodIfProxy, we want to actual class.
    385 
    386   art::ScopedObjectAccess soa(art::Thread::Current());
    387   art::mirror::Class* klass = art_method->GetDeclaringClass();
    388   *declaring_class_ptr = soa.AddLocalReference<jclass>(klass);
    389 
    390   return ERR(NONE);
    391 }
    392 
    393 jvmtiError MethodUtil::GetMethodLocation(jvmtiEnv* env ATTRIBUTE_UNUSED,
    394                                          jmethodID method,
    395                                          jlocation* start_location_ptr,
    396                                          jlocation* end_location_ptr) {
    397   if (method == nullptr) {
    398     return ERR(INVALID_METHODID);
    399   }
    400   art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
    401 
    402   if (art_method->IsNative()) {
    403     return ERR(NATIVE_METHOD);
    404   }
    405 
    406   if (start_location_ptr == nullptr || end_location_ptr == nullptr) {
    407     return ERR(NULL_POINTER);
    408   }
    409 
    410   art::ScopedObjectAccess soa(art::Thread::Current());
    411   if (art_method->IsProxyMethod() || art_method->IsAbstract()) {
    412     // This isn't specified as an error case, so return -1/-1 as the RI does.
    413     *start_location_ptr = -1;
    414     *end_location_ptr = -1;
    415     return ERR(NONE);
    416   }
    417 
    418   DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
    419   *start_location_ptr = 0;
    420   *end_location_ptr = art_method->DexInstructions().InsnsSizeInCodeUnits() - 1;
    421 
    422   return ERR(NONE);
    423 }
    424 
    425 jvmtiError MethodUtil::GetMethodModifiers(jvmtiEnv* env ATTRIBUTE_UNUSED,
    426                                           jmethodID method,
    427                                           jint* modifiers_ptr) {
    428   if (modifiers_ptr == nullptr) {
    429     return ERR(NULL_POINTER);
    430   }
    431 
    432   art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
    433   uint32_t modifiers = art_method->GetAccessFlags();
    434 
    435   // Note: Keep this code in sync with Executable.fixMethodFlags.
    436   if ((modifiers & art::kAccAbstract) != 0) {
    437     modifiers &= ~art::kAccNative;
    438   }
    439   modifiers &= ~art::kAccSynchronized;
    440   if ((modifiers & art::kAccDeclaredSynchronized) != 0) {
    441     modifiers |= art::kAccSynchronized;
    442   }
    443   modifiers &= art::kAccJavaFlagsMask;
    444 
    445   *modifiers_ptr = modifiers;
    446   return ERR(NONE);
    447 }
    448 
    449 using LineNumberContext = std::vector<jvmtiLineNumberEntry>;
    450 
    451 static bool CollectLineNumbers(void* void_context, const art::DexFile::PositionInfo& entry) {
    452   LineNumberContext* context = reinterpret_cast<LineNumberContext*>(void_context);
    453   jvmtiLineNumberEntry jvmti_entry = { static_cast<jlocation>(entry.address_),
    454                                        static_cast<jint>(entry.line_) };
    455   context->push_back(jvmti_entry);
    456   return false;  // Collect all, no early exit.
    457 }
    458 
    459 jvmtiError MethodUtil::GetLineNumberTable(jvmtiEnv* env,
    460                                           jmethodID method,
    461                                           jint* entry_count_ptr,
    462                                           jvmtiLineNumberEntry** table_ptr) {
    463   if (method == nullptr) {
    464     return ERR(NULL_POINTER);
    465   }
    466   art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
    467   DCHECK(!art_method->IsRuntimeMethod());
    468 
    469   art::CodeItemDebugInfoAccessor accessor;
    470   const art::DexFile* dex_file;
    471   {
    472     art::ScopedObjectAccess soa(art::Thread::Current());
    473 
    474     if (art_method->IsProxyMethod()) {
    475       return ERR(ABSENT_INFORMATION);
    476     }
    477     if (art_method->IsNative()) {
    478       return ERR(NATIVE_METHOD);
    479     }
    480     if (entry_count_ptr == nullptr || table_ptr == nullptr) {
    481       return ERR(NULL_POINTER);
    482     }
    483 
    484     accessor = art::CodeItemDebugInfoAccessor(art_method->DexInstructionDebugInfo());
    485     dex_file = art_method->GetDexFile();
    486     DCHECK(accessor.HasCodeItem()) << art_method->PrettyMethod() << " " << dex_file->GetLocation();
    487   }
    488 
    489   LineNumberContext context;
    490   bool success = dex_file->DecodeDebugPositionInfo(
    491       accessor.DebugInfoOffset(), CollectLineNumbers, &context);
    492   if (!success) {
    493     return ERR(ABSENT_INFORMATION);
    494   }
    495 
    496   unsigned char* data;
    497   jlong mem_size = context.size() * sizeof(jvmtiLineNumberEntry);
    498   jvmtiError alloc_error = env->Allocate(mem_size, &data);
    499   if (alloc_error != ERR(NONE)) {
    500     return alloc_error;
    501   }
    502   *table_ptr = reinterpret_cast<jvmtiLineNumberEntry*>(data);
    503   memcpy(*table_ptr, context.data(), mem_size);
    504   *entry_count_ptr = static_cast<jint>(context.size());
    505 
    506   return ERR(NONE);
    507 }
    508 
    509 template <typename T>
    510 static jvmtiError IsMethodT(jvmtiEnv* env ATTRIBUTE_UNUSED,
    511                             jmethodID method,
    512                             T test,
    513                             jboolean* is_t_ptr) {
    514   if (method == nullptr) {
    515     return ERR(INVALID_METHODID);
    516   }
    517   if (is_t_ptr == nullptr) {
    518     return ERR(NULL_POINTER);
    519   }
    520 
    521   art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
    522   *is_t_ptr = test(art_method) ? JNI_TRUE : JNI_FALSE;
    523 
    524   return ERR(NONE);
    525 }
    526 
    527 jvmtiError MethodUtil::IsMethodNative(jvmtiEnv* env, jmethodID m, jboolean* is_native_ptr) {
    528   auto test = [](art::ArtMethod* method) {
    529     return method->IsNative();
    530   };
    531   return IsMethodT(env, m, test, is_native_ptr);
    532 }
    533 
    534 jvmtiError MethodUtil::IsMethodObsolete(jvmtiEnv* env, jmethodID m, jboolean* is_obsolete_ptr) {
    535   auto test = [](art::ArtMethod* method) {
    536     return method->IsObsolete();
    537   };
    538   return IsMethodT(env, m, test, is_obsolete_ptr);
    539 }
    540 
    541 jvmtiError MethodUtil::IsMethodSynthetic(jvmtiEnv* env, jmethodID m, jboolean* is_synthetic_ptr) {
    542   auto test = [](art::ArtMethod* method) {
    543     return method->IsSynthetic();
    544   };
    545   return IsMethodT(env, m, test, is_synthetic_ptr);
    546 }
    547 
    548 class CommonLocalVariableClosure : public art::Closure {
    549  public:
    550   CommonLocalVariableClosure(jint depth, jint slot)
    551       : result_(ERR(INTERNAL)), depth_(depth), slot_(slot) {}
    552 
    553   void Run(art::Thread* self) OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
    554     art::Locks::mutator_lock_->AssertSharedHeld(art::Thread::Current());
    555     art::ScopedAssertNoThreadSuspension sants("CommonLocalVariableClosure::Run");
    556     std::unique_ptr<art::Context> context(art::Context::Create());
    557     FindFrameAtDepthVisitor visitor(self, context.get(), depth_);
    558     visitor.WalkStack();
    559     if (!visitor.FoundFrame()) {
    560       // Must have been a bad depth.
    561       result_ = ERR(NO_MORE_FRAMES);
    562       return;
    563     }
    564     art::ArtMethod* method = visitor.GetMethod();
    565     // Native and 'art' proxy methods don't have registers.
    566     if (method->IsNative() || method->IsProxyMethod()) {
    567       // TODO It might be useful to fake up support for get at least on proxy frames.
    568       result_ = ERR(OPAQUE_FRAME);
    569       return;
    570     } else if (method->DexInstructionData().RegistersSize() <= slot_) {
    571       result_ = ERR(INVALID_SLOT);
    572       return;
    573     }
    574     bool needs_instrument = !visitor.IsShadowFrame();
    575     uint32_t pc = visitor.GetDexPc(/*abort_on_failure*/ false);
    576     if (pc == art::dex::kDexNoIndex) {
    577       // Cannot figure out current PC.
    578       result_ = ERR(OPAQUE_FRAME);
    579       return;
    580     }
    581     std::string descriptor;
    582     art::Primitive::Type slot_type = art::Primitive::kPrimVoid;
    583     jvmtiError err = GetSlotType(method, pc, &descriptor, &slot_type);
    584     if (err != OK) {
    585       result_ = err;
    586       return;
    587     }
    588 
    589     err = GetTypeError(method, slot_type, descriptor);
    590     if (err != OK) {
    591       result_ = err;
    592       return;
    593     }
    594     result_ = Execute(method, visitor);
    595     if (needs_instrument) {
    596       art::Runtime::Current()->GetInstrumentation()->InstrumentThreadStack(self);
    597     }
    598   }
    599 
    600   virtual jvmtiError GetResult() {
    601     return result_;
    602   }
    603 
    604  protected:
    605   virtual jvmtiError Execute(art::ArtMethod* method, art::StackVisitor& visitor)
    606       REQUIRES_SHARED(art::Locks::mutator_lock_) = 0;
    607   virtual jvmtiError GetTypeError(art::ArtMethod* method,
    608                                   art::Primitive::Type type,
    609                                   const std::string& descriptor)
    610       REQUIRES_SHARED(art::Locks::mutator_lock_)  = 0;
    611 
    612   jvmtiError GetSlotType(art::ArtMethod* method,
    613                          uint32_t dex_pc,
    614                          /*out*/std::string* descriptor,
    615                          /*out*/art::Primitive::Type* type)
    616       REQUIRES(art::Locks::mutator_lock_) {
    617     const art::DexFile* dex_file = method->GetDexFile();
    618     if (dex_file == nullptr) {
    619       return ERR(OPAQUE_FRAME);
    620     }
    621     art::CodeItemDebugInfoAccessor accessor(method->DexInstructionDebugInfo());
    622     if (!accessor.HasCodeItem()) {
    623       return ERR(OPAQUE_FRAME);
    624     }
    625 
    626     struct GetLocalVariableInfoContext {
    627       explicit GetLocalVariableInfoContext(jint slot,
    628                                           uint32_t pc,
    629                                           std::string* out_descriptor,
    630                                           art::Primitive::Type* out_type)
    631           : found_(false), jslot_(slot), pc_(pc), descriptor_(out_descriptor), type_(out_type) {
    632         *descriptor_ = "";
    633         *type_ = art::Primitive::kPrimVoid;
    634       }
    635 
    636       static void Callback(void* raw_ctx, const art::DexFile::LocalInfo& entry) {
    637         reinterpret_cast<GetLocalVariableInfoContext*>(raw_ctx)->Handle(entry);
    638       }
    639 
    640       void Handle(const art::DexFile::LocalInfo& entry) {
    641         if (found_) {
    642           return;
    643         } else if (entry.start_address_ <= pc_ &&
    644                    entry.end_address_ > pc_ &&
    645                    entry.reg_ == jslot_) {
    646           found_ = true;
    647           *type_ = art::Primitive::GetType(entry.descriptor_[0]);
    648           *descriptor_ = entry.descriptor_;
    649         }
    650         return;
    651       }
    652 
    653       bool found_;
    654       jint jslot_;
    655       uint32_t pc_;
    656       std::string* descriptor_;
    657       art::Primitive::Type* type_;
    658     };
    659 
    660     GetLocalVariableInfoContext context(slot_, dex_pc, descriptor, type);
    661     if (!dex_file->DecodeDebugLocalInfo(accessor.RegistersSize(),
    662                                         accessor.InsSize(),
    663                                         accessor.InsnsSizeInCodeUnits(),
    664                                         accessor.DebugInfoOffset(),
    665                                         method->IsStatic(),
    666                                         method->GetDexMethodIndex(),
    667                                         GetLocalVariableInfoContext::Callback,
    668                                         &context) || !context.found_) {
    669       // Something went wrong with decoding the debug information. It might as well not be there.
    670       return ERR(INVALID_SLOT);
    671     } else {
    672       return OK;
    673     }
    674   }
    675 
    676   jvmtiError result_;
    677   jint depth_;
    678   jint slot_;
    679 };
    680 
    681 class GetLocalVariableClosure : public CommonLocalVariableClosure {
    682  public:
    683   GetLocalVariableClosure(jint depth,
    684                           jint slot,
    685                           art::Primitive::Type type,
    686                           jvalue* val)
    687       : CommonLocalVariableClosure(depth, slot),
    688         type_(type),
    689         val_(val),
    690         obj_val_(nullptr) {}
    691 
    692   virtual jvmtiError GetResult() REQUIRES_SHARED(art::Locks::mutator_lock_) {
    693     if (result_ == OK && type_ == art::Primitive::kPrimNot) {
    694       val_->l = obj_val_.IsNull()
    695           ? nullptr
    696           : art::Thread::Current()->GetJniEnv()->AddLocalReference<jobject>(obj_val_.Read());
    697     }
    698     return CommonLocalVariableClosure::GetResult();
    699   }
    700 
    701  protected:
    702   jvmtiError GetTypeError(art::ArtMethod* method ATTRIBUTE_UNUSED,
    703                           art::Primitive::Type slot_type,
    704                           const std::string& descriptor ATTRIBUTE_UNUSED)
    705       OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
    706     switch (slot_type) {
    707       case art::Primitive::kPrimByte:
    708       case art::Primitive::kPrimChar:
    709       case art::Primitive::kPrimInt:
    710       case art::Primitive::kPrimShort:
    711       case art::Primitive::kPrimBoolean:
    712         return type_ == art::Primitive::kPrimInt ? OK : ERR(TYPE_MISMATCH);
    713       case art::Primitive::kPrimLong:
    714       case art::Primitive::kPrimFloat:
    715       case art::Primitive::kPrimDouble:
    716       case art::Primitive::kPrimNot:
    717         return type_ == slot_type ? OK : ERR(TYPE_MISMATCH);
    718       case art::Primitive::kPrimVoid:
    719         LOG(FATAL) << "Unexpected primitive type " << slot_type;
    720         UNREACHABLE();
    721     }
    722   }
    723 
    724   jvmtiError Execute(art::ArtMethod* method, art::StackVisitor& visitor)
    725       OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
    726     switch (type_) {
    727       case art::Primitive::kPrimNot: {
    728         uint32_t ptr_val;
    729         if (!visitor.GetVReg(method,
    730                              static_cast<uint16_t>(slot_),
    731                              art::kReferenceVReg,
    732                              &ptr_val)) {
    733           return ERR(OPAQUE_FRAME);
    734         }
    735         obj_val_ = art::GcRoot<art::mirror::Object>(
    736             reinterpret_cast<art::mirror::Object*>(ptr_val));
    737         break;
    738       }
    739       case art::Primitive::kPrimInt:
    740       case art::Primitive::kPrimFloat: {
    741         if (!visitor.GetVReg(method,
    742                              static_cast<uint16_t>(slot_),
    743                              type_ == art::Primitive::kPrimFloat ? art::kFloatVReg : art::kIntVReg,
    744                              reinterpret_cast<uint32_t*>(&val_->i))) {
    745           return ERR(OPAQUE_FRAME);
    746         }
    747         break;
    748       }
    749       case art::Primitive::kPrimDouble:
    750       case art::Primitive::kPrimLong: {
    751         auto lo_type = type_ == art::Primitive::kPrimLong ? art::kLongLoVReg : art::kDoubleLoVReg;
    752         auto high_type = type_ == art::Primitive::kPrimLong ? art::kLongHiVReg : art::kDoubleHiVReg;
    753         if (!visitor.GetVRegPair(method,
    754                                  static_cast<uint16_t>(slot_),
    755                                  lo_type,
    756                                  high_type,
    757                                  reinterpret_cast<uint64_t*>(&val_->j))) {
    758           return ERR(OPAQUE_FRAME);
    759         }
    760         break;
    761       }
    762       default: {
    763         LOG(FATAL) << "unexpected register type " << type_;
    764         UNREACHABLE();
    765       }
    766     }
    767     return OK;
    768   }
    769 
    770  private:
    771   art::Primitive::Type type_;
    772   jvalue* val_;
    773   art::GcRoot<art::mirror::Object> obj_val_;
    774 };
    775 
    776 jvmtiError MethodUtil::GetLocalVariableGeneric(jvmtiEnv* env ATTRIBUTE_UNUSED,
    777                                                jthread thread,
    778                                                jint depth,
    779                                                jint slot,
    780                                                art::Primitive::Type type,
    781                                                jvalue* val) {
    782   if (depth < 0) {
    783     return ERR(ILLEGAL_ARGUMENT);
    784   }
    785   art::Thread* self = art::Thread::Current();
    786   // Suspend JIT since it can get confused if we deoptimize methods getting jitted.
    787   art::jit::ScopedJitSuspend suspend_jit;
    788   art::ScopedObjectAccess soa(self);
    789   art::Locks::thread_list_lock_->ExclusiveLock(self);
    790   art::Thread* target = nullptr;
    791   jvmtiError err = ERR(INTERNAL);
    792   if (!ThreadUtil::GetAliveNativeThread(thread, soa, &target, &err)) {
    793     art::Locks::thread_list_lock_->ExclusiveUnlock(self);
    794     return err;
    795   }
    796   art::ScopedAssertNoThreadSuspension sants("Performing GetLocalVariable");
    797   GetLocalVariableClosure c(depth, slot, type, val);
    798   // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.  We
    799   // need to avoid suspending as we wait for the checkpoint to occur since we are (potentially)
    800   // transfering a GcRoot across threads.
    801   if (!target->RequestSynchronousCheckpoint(&c, art::ThreadState::kRunnable)) {
    802     return ERR(THREAD_NOT_ALIVE);
    803   } else {
    804     return c.GetResult();
    805   }
    806 }
    807 
    808 class SetLocalVariableClosure : public CommonLocalVariableClosure {
    809  public:
    810   SetLocalVariableClosure(art::Thread* caller,
    811                           jint depth,
    812                           jint slot,
    813                           art::Primitive::Type type,
    814                           jvalue val)
    815       : CommonLocalVariableClosure(depth, slot), caller_(caller), type_(type), val_(val) {}
    816 
    817  protected:
    818   jvmtiError GetTypeError(art::ArtMethod* method,
    819                           art::Primitive::Type slot_type,
    820                           const std::string& descriptor)
    821       OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
    822     switch (slot_type) {
    823       case art::Primitive::kPrimNot: {
    824         if (type_ != art::Primitive::kPrimNot) {
    825           return ERR(TYPE_MISMATCH);
    826         } else if (val_.l == nullptr) {
    827           return OK;
    828         } else {
    829           art::ClassLinker* cl = art::Runtime::Current()->GetClassLinker();
    830           art::ObjPtr<art::mirror::Class> set_class =
    831               caller_->DecodeJObject(val_.l)->GetClass();
    832           art::ObjPtr<art::mirror::ClassLoader> loader =
    833               method->GetDeclaringClass()->GetClassLoader();
    834           art::ObjPtr<art::mirror::Class> slot_class =
    835               cl->LookupClass(caller_, descriptor.c_str(), loader);
    836           DCHECK(!slot_class.IsNull());
    837           return slot_class->IsAssignableFrom(set_class) ? OK : ERR(TYPE_MISMATCH);
    838         }
    839       }
    840       case art::Primitive::kPrimByte:
    841       case art::Primitive::kPrimChar:
    842       case art::Primitive::kPrimInt:
    843       case art::Primitive::kPrimShort:
    844       case art::Primitive::kPrimBoolean:
    845         return type_ == art::Primitive::kPrimInt ? OK : ERR(TYPE_MISMATCH);
    846       case art::Primitive::kPrimLong:
    847       case art::Primitive::kPrimFloat:
    848       case art::Primitive::kPrimDouble:
    849         return type_ == slot_type ? OK : ERR(TYPE_MISMATCH);
    850       case art::Primitive::kPrimVoid:
    851         LOG(FATAL) << "Unexpected primitive type " << slot_type;
    852         UNREACHABLE();
    853     }
    854   }
    855 
    856   jvmtiError Execute(art::ArtMethod* method, art::StackVisitor& visitor)
    857       OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
    858     switch (type_) {
    859       case art::Primitive::kPrimNot: {
    860         uint32_t ptr_val;
    861         art::ObjPtr<art::mirror::Object> obj(caller_->DecodeJObject(val_.l));
    862         ptr_val = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(obj.Ptr()));
    863         if (!visitor.SetVReg(method,
    864                              static_cast<uint16_t>(slot_),
    865                              ptr_val,
    866                              art::kReferenceVReg)) {
    867           return ERR(OPAQUE_FRAME);
    868         }
    869         break;
    870       }
    871       case art::Primitive::kPrimInt:
    872       case art::Primitive::kPrimFloat: {
    873         if (!visitor.SetVReg(method,
    874                              static_cast<uint16_t>(slot_),
    875                              static_cast<uint32_t>(val_.i),
    876                              type_ == art::Primitive::kPrimFloat ? art::kFloatVReg
    877                                                                  : art::kIntVReg)) {
    878           return ERR(OPAQUE_FRAME);
    879         }
    880         break;
    881       }
    882       case art::Primitive::kPrimDouble:
    883       case art::Primitive::kPrimLong: {
    884         auto lo_type = type_ == art::Primitive::kPrimLong ? art::kLongLoVReg : art::kDoubleLoVReg;
    885         auto high_type = type_ == art::Primitive::kPrimLong ? art::kLongHiVReg : art::kDoubleHiVReg;
    886         if (!visitor.SetVRegPair(method,
    887                                  static_cast<uint16_t>(slot_),
    888                                  static_cast<uint64_t>(val_.j),
    889                                  lo_type,
    890                                  high_type)) {
    891           return ERR(OPAQUE_FRAME);
    892         }
    893         break;
    894       }
    895       default: {
    896         LOG(FATAL) << "unexpected register type " << type_;
    897         UNREACHABLE();
    898       }
    899     }
    900     return OK;
    901   }
    902 
    903  private:
    904   art::Thread* caller_;
    905   art::Primitive::Type type_;
    906   jvalue val_;
    907 };
    908 
    909 jvmtiError MethodUtil::SetLocalVariableGeneric(jvmtiEnv* env ATTRIBUTE_UNUSED,
    910                                                jthread thread,
    911                                                jint depth,
    912                                                jint slot,
    913                                                art::Primitive::Type type,
    914                                                jvalue val) {
    915   if (depth < 0) {
    916     return ERR(ILLEGAL_ARGUMENT);
    917   }
    918   // Make sure that we know not to do any OSR anymore.
    919   // TODO We should really keep track of this at the Frame granularity.
    920   DeoptManager::Get()->SetLocalsUpdated();
    921   art::Thread* self = art::Thread::Current();
    922   // Suspend JIT since it can get confused if we deoptimize methods getting jitted.
    923   art::jit::ScopedJitSuspend suspend_jit;
    924   art::ScopedObjectAccess soa(self);
    925   art::Locks::thread_list_lock_->ExclusiveLock(self);
    926   art::Thread* target = nullptr;
    927   jvmtiError err = ERR(INTERNAL);
    928   if (!ThreadUtil::GetAliveNativeThread(thread, soa, &target, &err)) {
    929     art::Locks::thread_list_lock_->ExclusiveUnlock(self);
    930     return err;
    931   }
    932   SetLocalVariableClosure c(self, depth, slot, type, val);
    933   // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
    934   if (!target->RequestSynchronousCheckpoint(&c)) {
    935     return ERR(THREAD_NOT_ALIVE);
    936   } else {
    937     return c.GetResult();
    938   }
    939 }
    940 
    941 class GetLocalInstanceClosure : public art::Closure {
    942  public:
    943   explicit GetLocalInstanceClosure(jint depth)
    944       : result_(ERR(INTERNAL)),
    945         depth_(depth),
    946         val_(nullptr) {}
    947 
    948   void Run(art::Thread* self) OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
    949     art::ScopedAssertNoThreadSuspension sants("GetLocalInstanceClosure::Run");
    950     art::Locks::mutator_lock_->AssertSharedHeld(art::Thread::Current());
    951     std::unique_ptr<art::Context> context(art::Context::Create());
    952     FindFrameAtDepthVisitor visitor(self, context.get(), depth_);
    953     visitor.WalkStack();
    954     if (!visitor.FoundFrame()) {
    955       // Must have been a bad depth.
    956       result_ = ERR(NO_MORE_FRAMES);
    957       return;
    958     }
    959     result_ = OK;
    960     val_ = art::GcRoot<art::mirror::Object>(visitor.GetThisObject());
    961   }
    962 
    963   jvmtiError GetResult(jobject* data_out) REQUIRES_SHARED(art::Locks::mutator_lock_) {
    964     if (result_ == OK) {
    965       *data_out = val_.IsNull()
    966           ? nullptr
    967           : art::Thread::Current()->GetJniEnv()->AddLocalReference<jobject>(val_.Read());
    968     }
    969     return result_;
    970   }
    971 
    972  private:
    973   jvmtiError result_;
    974   jint depth_;
    975   art::GcRoot<art::mirror::Object> val_;
    976 };
    977 
    978 jvmtiError MethodUtil::GetLocalInstance(jvmtiEnv* env ATTRIBUTE_UNUSED,
    979                                         jthread thread,
    980                                         jint depth,
    981                                         jobject* data) {
    982   if (depth < 0) {
    983     return ERR(ILLEGAL_ARGUMENT);
    984   }
    985   art::Thread* self = art::Thread::Current();
    986   art::ScopedObjectAccess soa(self);
    987   art::Locks::thread_list_lock_->ExclusiveLock(self);
    988   art::Thread* target = nullptr;
    989   jvmtiError err = ERR(INTERNAL);
    990   if (!ThreadUtil::GetAliveNativeThread(thread, soa, &target, &err)) {
    991     art::Locks::thread_list_lock_->ExclusiveUnlock(self);
    992     return err;
    993   }
    994   art::ScopedAssertNoThreadSuspension sants("Performing GetLocalInstance");
    995   GetLocalInstanceClosure c(depth);
    996   // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.  We
    997   // need to avoid suspending as we wait for the checkpoint to occur since we are (potentially)
    998   // transfering a GcRoot across threads.
    999   if (!target->RequestSynchronousCheckpoint(&c, art::ThreadState::kRunnable)) {
   1000     return ERR(THREAD_NOT_ALIVE);
   1001   } else {
   1002     return c.GetResult(data);
   1003   }
   1004 }
   1005 
   1006 #define FOR_JVMTI_JVALUE_TYPES(fn) \
   1007     fn(jint, art::Primitive::kPrimInt, i) \
   1008     fn(jlong, art::Primitive::kPrimLong, j) \
   1009     fn(jfloat, art::Primitive::kPrimFloat, f) \
   1010     fn(jdouble, art::Primitive::kPrimDouble, d) \
   1011     fn(jobject, art::Primitive::kPrimNot, l)
   1012 
   1013 namespace impl {
   1014 
   1015 template<typename T> void WriteJvalue(T, jvalue*);
   1016 template<typename T> void ReadJvalue(jvalue, T*);
   1017 template<typename T> art::Primitive::Type GetJNIType();
   1018 
   1019 #define JNI_TYPE_CHAR(type, prim, id) \
   1020 template<> art::Primitive::Type GetJNIType<type>() { \
   1021   return prim; \
   1022 }
   1023 
   1024 FOR_JVMTI_JVALUE_TYPES(JNI_TYPE_CHAR);
   1025 
   1026 #undef JNI_TYPE_CHAR
   1027 
   1028 #define RW_JVALUE(srctype, prim, id) \
   1029     template<> void ReadJvalue<srctype>(jvalue in, std::add_pointer<srctype>::type out) { \
   1030       *out = in.id; \
   1031     } \
   1032     template<> void WriteJvalue<srctype>(srctype in, jvalue* out) { \
   1033       out->id = in; \
   1034     }
   1035 
   1036 FOR_JVMTI_JVALUE_TYPES(RW_JVALUE);
   1037 
   1038 #undef RW_JVALUE
   1039 
   1040 }  // namespace impl
   1041 
   1042 template<typename T>
   1043 jvmtiError MethodUtil::SetLocalVariable(jvmtiEnv* env,
   1044                                         jthread thread,
   1045                                         jint depth,
   1046                                         jint slot,
   1047                                         T data) {
   1048   jvalue v = {.j = 0};
   1049   art::Primitive::Type type = impl::GetJNIType<T>();
   1050   impl::WriteJvalue(data, &v);
   1051   return SetLocalVariableGeneric(env, thread, depth, slot, type, v);
   1052 }
   1053 
   1054 template<typename T>
   1055 jvmtiError MethodUtil::GetLocalVariable(jvmtiEnv* env,
   1056                                         jthread thread,
   1057                                         jint depth,
   1058                                         jint slot,
   1059                                         T* data) {
   1060   if (data == nullptr) {
   1061     return ERR(NULL_POINTER);
   1062   }
   1063   jvalue v = {.j = 0};
   1064   art::Primitive::Type type = impl::GetJNIType<T>();
   1065   jvmtiError err = GetLocalVariableGeneric(env, thread, depth, slot, type, &v);
   1066   if (err != OK) {
   1067     return err;
   1068   } else {
   1069     impl::ReadJvalue(v, data);
   1070     return OK;
   1071   }
   1072 }
   1073 
   1074 #define GET_SET_LV(srctype, prim, id) \
   1075     template jvmtiError MethodUtil::GetLocalVariable<srctype>(jvmtiEnv*, \
   1076                                                               jthread, \
   1077                                                               jint, \
   1078                                                               jint, \
   1079                                                               std::add_pointer<srctype>::type); \
   1080     template jvmtiError MethodUtil::SetLocalVariable<srctype>(jvmtiEnv*, \
   1081                                                               jthread, \
   1082                                                               jint, \
   1083                                                               jint, \
   1084                                                               srctype);
   1085 
   1086 FOR_JVMTI_JVALUE_TYPES(GET_SET_LV);
   1087 
   1088 #undef GET_SET_LV
   1089 
   1090 #undef FOR_JVMTI_JVALUE_TYPES
   1091 
   1092 }  // namespace openjdkjvmti
   1093