summaryrefslogtreecommitdiff
path: root/openjdkjvmti/OpenjdkJvmTi.cc
diff options
context:
space:
mode:
Diffstat (limited to 'openjdkjvmti/OpenjdkJvmTi.cc')
-rw-r--r--openjdkjvmti/OpenjdkJvmTi.cc1903
1 files changed, 1903 insertions, 0 deletions
diff --git a/openjdkjvmti/OpenjdkJvmTi.cc b/openjdkjvmti/OpenjdkJvmTi.cc
new file mode 100644
index 0000000000..af770724ab
--- /dev/null
+++ b/openjdkjvmti/OpenjdkJvmTi.cc
@@ -0,0 +1,1903 @@
+/* Copyright (C) 2016 The Android Open Source Project
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This file implements interfaces from the file jvmti.h. This implementation
+ * is licensed under the same terms as the file jvmti.h. The
+ * copyright and license information for the file jvmti.h follows.
+ *
+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include <jni.h>
+
+#include "jvmti.h"
+
+#include "art_jvmti.h"
+#include "base/logging.h"
+#include "base/mutex.h"
+#include "events-inl.h"
+#include "jni_env_ext-inl.h"
+#include "obj_ptr-inl.h"
+#include "object_tagging.h"
+#include "runtime.h"
+#include "scoped_thread_state_change-inl.h"
+#include "thread-current-inl.h"
+#include "thread_list.h"
+#include "ti_allocator.h"
+#include "ti_breakpoint.h"
+#include "ti_class.h"
+#include "ti_dump.h"
+#include "ti_field.h"
+#include "ti_heap.h"
+#include "ti_jni.h"
+#include "ti_method.h"
+#include "ti_monitor.h"
+#include "ti_object.h"
+#include "ti_phase.h"
+#include "ti_properties.h"
+#include "ti_redefine.h"
+#include "ti_search.h"
+#include "ti_stack.h"
+#include "ti_thread.h"
+#include "ti_threadgroup.h"
+#include "ti_timers.h"
+#include "transform.h"
+
+namespace openjdkjvmti {
+
+EventHandler gEventHandler;
+
+#define ENSURE_NON_NULL(n) \
+ do { \
+ if ((n) == nullptr) { \
+ return ERR(NULL_POINTER); \
+ } \
+ } while (false)
+
+class JvmtiFunctions {
+ private:
+ static jvmtiError getEnvironmentError(jvmtiEnv* env) {
+ if (env == nullptr) {
+ return ERR(INVALID_ENVIRONMENT);
+ } else if (art::Thread::Current() == nullptr) {
+ return ERR(UNATTACHED_THREAD);
+ } else {
+ return OK;
+ }
+ }
+
+#define ENSURE_VALID_ENV(env) \
+ do { \
+ jvmtiError ensure_valid_env_ ## __LINE__ = getEnvironmentError(env); \
+ if (ensure_valid_env_ ## __LINE__ != OK) { \
+ return ensure_valid_env_ ## __LINE__ ; \
+ } \
+ } while (false)
+
+#define ENSURE_HAS_CAP(env, cap) \
+ do { \
+ if (ArtJvmTiEnv::AsArtJvmTiEnv(env)->capabilities.cap != 1) { \
+ return ERR(MUST_POSSESS_CAPABILITY); \
+ } \
+ } while (false)
+
+ public:
+ static jvmtiError Allocate(jvmtiEnv* env, jlong size, unsigned char** mem_ptr) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_NON_NULL(mem_ptr);
+ return AllocUtil::Allocate(env, size, mem_ptr);
+ }
+
+ static jvmtiError Deallocate(jvmtiEnv* env, unsigned char* mem) {
+ ENSURE_VALID_ENV(env);
+ return AllocUtil::Deallocate(env, mem);
+ }
+
+ static jvmtiError GetThreadState(jvmtiEnv* env, jthread thread, jint* thread_state_ptr) {
+ ENSURE_VALID_ENV(env);
+ return ThreadUtil::GetThreadState(env, thread, thread_state_ptr);
+ }
+
+ static jvmtiError GetCurrentThread(jvmtiEnv* env, jthread* thread_ptr) {
+ ENSURE_VALID_ENV(env);
+ return ThreadUtil::GetCurrentThread(env, thread_ptr);
+ }
+
+ static jvmtiError GetAllThreads(jvmtiEnv* env, jint* threads_count_ptr, jthread** threads_ptr) {
+ ENSURE_VALID_ENV(env);
+ return ThreadUtil::GetAllThreads(env, threads_count_ptr, threads_ptr);
+ }
+
+ static jvmtiError SuspendThread(jvmtiEnv* env, jthread thread) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_suspend);
+ return ThreadUtil::SuspendThread(env, thread);
+ }
+
+ static jvmtiError SuspendThreadList(jvmtiEnv* env,
+ jint request_count,
+ const jthread* request_list,
+ jvmtiError* results) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_suspend);
+ return ThreadUtil::SuspendThreadList(env, request_count, request_list, results);
+ }
+
+ static jvmtiError ResumeThread(jvmtiEnv* env, jthread thread) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_suspend);
+ return ThreadUtil::ResumeThread(env, thread);
+ }
+
+ static jvmtiError ResumeThreadList(jvmtiEnv* env,
+ jint request_count,
+ const jthread* request_list,
+ jvmtiError* results) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_suspend);
+ return ThreadUtil::ResumeThreadList(env, request_count, request_list, results);
+ }
+
+ static jvmtiError StopThread(jvmtiEnv* env,
+ jthread thread ATTRIBUTE_UNUSED,
+ jobject exception ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_signal_thread);
+ return ERR(NOT_IMPLEMENTED);
+ }
+
+ static jvmtiError InterruptThread(jvmtiEnv* env, jthread thread ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_signal_thread);
+ return ERR(NOT_IMPLEMENTED);
+ }
+
+ static jvmtiError GetThreadInfo(jvmtiEnv* env, jthread thread, jvmtiThreadInfo* info_ptr) {
+ ENSURE_VALID_ENV(env);
+ return ThreadUtil::GetThreadInfo(env, thread, info_ptr);
+ }
+
+ static jvmtiError GetOwnedMonitorInfo(jvmtiEnv* env,
+ jthread thread ATTRIBUTE_UNUSED,
+ jint* owned_monitor_count_ptr ATTRIBUTE_UNUSED,
+ jobject** owned_monitors_ptr ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_get_owned_monitor_info);
+ return ERR(NOT_IMPLEMENTED);
+ }
+
+ static jvmtiError GetOwnedMonitorStackDepthInfo(
+ jvmtiEnv* env,
+ jthread thread ATTRIBUTE_UNUSED,
+ jint* monitor_info_count_ptr ATTRIBUTE_UNUSED,
+ jvmtiMonitorStackDepthInfo** monitor_info_ptr ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_get_owned_monitor_stack_depth_info);
+ return ERR(NOT_IMPLEMENTED);
+ }
+
+ static jvmtiError GetCurrentContendedMonitor(jvmtiEnv* env,
+ jthread thread ATTRIBUTE_UNUSED,
+ jobject* monitor_ptr ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_get_current_contended_monitor);
+ return ERR(NOT_IMPLEMENTED);
+ }
+
+ static jvmtiError RunAgentThread(jvmtiEnv* env,
+ jthread thread,
+ jvmtiStartFunction proc,
+ const void* arg,
+ jint priority) {
+ ENSURE_VALID_ENV(env);
+ return ThreadUtil::RunAgentThread(env, thread, proc, arg, priority);
+ }
+
+ static jvmtiError SetThreadLocalStorage(jvmtiEnv* env, jthread thread, const void* data) {
+ ENSURE_VALID_ENV(env);
+ return ThreadUtil::SetThreadLocalStorage(env, thread, data);
+ }
+
+ static jvmtiError GetThreadLocalStorage(jvmtiEnv* env, jthread thread, void** data_ptr) {
+ ENSURE_VALID_ENV(env);
+ return ThreadUtil::GetThreadLocalStorage(env, thread, data_ptr);
+ }
+
+ static jvmtiError GetTopThreadGroups(jvmtiEnv* env,
+ jint* group_count_ptr,
+ jthreadGroup** groups_ptr) {
+ ENSURE_VALID_ENV(env);
+ return ThreadGroupUtil::GetTopThreadGroups(env, group_count_ptr, groups_ptr);
+ }
+
+ static jvmtiError GetThreadGroupInfo(jvmtiEnv* env,
+ jthreadGroup group,
+ jvmtiThreadGroupInfo* info_ptr) {
+ ENSURE_VALID_ENV(env);
+ return ThreadGroupUtil::GetThreadGroupInfo(env, group, info_ptr);
+ }
+
+ static jvmtiError GetThreadGroupChildren(jvmtiEnv* env,
+ jthreadGroup group,
+ jint* thread_count_ptr,
+ jthread** threads_ptr,
+ jint* group_count_ptr,
+ jthreadGroup** groups_ptr) {
+ ENSURE_VALID_ENV(env);
+ return ThreadGroupUtil::GetThreadGroupChildren(env,
+ group,
+ thread_count_ptr,
+ threads_ptr,
+ group_count_ptr,
+ groups_ptr);
+ }
+
+ static jvmtiError GetStackTrace(jvmtiEnv* env,
+ jthread thread,
+ jint start_depth,
+ jint max_frame_count,
+ jvmtiFrameInfo* frame_buffer,
+ jint* count_ptr) {
+ ENSURE_VALID_ENV(env);
+ return StackUtil::GetStackTrace(env,
+ thread,
+ start_depth,
+ max_frame_count,
+ frame_buffer,
+ count_ptr);
+ }
+
+ static jvmtiError GetAllStackTraces(jvmtiEnv* env,
+ jint max_frame_count,
+ jvmtiStackInfo** stack_info_ptr,
+ jint* thread_count_ptr) {
+ ENSURE_VALID_ENV(env);
+ return StackUtil::GetAllStackTraces(env, max_frame_count, stack_info_ptr, thread_count_ptr);
+ }
+
+ static jvmtiError GetThreadListStackTraces(jvmtiEnv* env,
+ jint thread_count,
+ const jthread* thread_list,
+ jint max_frame_count,
+ jvmtiStackInfo** stack_info_ptr) {
+ ENSURE_VALID_ENV(env);
+ return StackUtil::GetThreadListStackTraces(env,
+ thread_count,
+ thread_list,
+ max_frame_count,
+ stack_info_ptr);
+ }
+
+ static jvmtiError GetFrameCount(jvmtiEnv* env, jthread thread, jint* count_ptr) {
+ ENSURE_VALID_ENV(env);
+ return StackUtil::GetFrameCount(env, thread, count_ptr);
+ }
+
+ static jvmtiError PopFrame(jvmtiEnv* env, jthread thread ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_pop_frame);
+ return ERR(NOT_IMPLEMENTED);
+ }
+
+ static jvmtiError GetFrameLocation(jvmtiEnv* env,
+ jthread thread,
+ jint depth,
+ jmethodID* method_ptr,
+ jlocation* location_ptr) {
+ ENSURE_VALID_ENV(env);
+ return StackUtil::GetFrameLocation(env, thread, depth, method_ptr, location_ptr);
+ }
+
+ static jvmtiError NotifyFramePop(jvmtiEnv* env,
+ jthread thread ATTRIBUTE_UNUSED,
+ jint depth ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_generate_frame_pop_events);
+ return ERR(NOT_IMPLEMENTED);
+ }
+
+ static jvmtiError ForceEarlyReturnObject(jvmtiEnv* env,
+ jthread thread ATTRIBUTE_UNUSED,
+ jobject value ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_force_early_return);
+ return ERR(NOT_IMPLEMENTED);
+ }
+
+ static jvmtiError ForceEarlyReturnInt(jvmtiEnv* env,
+ jthread thread ATTRIBUTE_UNUSED,
+ jint value ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_force_early_return);
+ return ERR(NOT_IMPLEMENTED);
+ }
+
+ static jvmtiError ForceEarlyReturnLong(jvmtiEnv* env,
+ jthread thread ATTRIBUTE_UNUSED,
+ jlong value ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_force_early_return);
+ return ERR(NOT_IMPLEMENTED);
+ }
+
+ static jvmtiError ForceEarlyReturnFloat(jvmtiEnv* env,
+ jthread thread ATTRIBUTE_UNUSED,
+ jfloat value ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_force_early_return);
+ return ERR(NOT_IMPLEMENTED);
+ }
+
+ static jvmtiError ForceEarlyReturnDouble(jvmtiEnv* env,
+ jthread thread ATTRIBUTE_UNUSED,
+ jdouble value ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_force_early_return);
+ return ERR(NOT_IMPLEMENTED);
+ }
+
+ static jvmtiError ForceEarlyReturnVoid(jvmtiEnv* env, jthread thread ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_force_early_return);
+ return ERR(NOT_IMPLEMENTED);
+ }
+
+ static jvmtiError FollowReferences(jvmtiEnv* env,
+ jint heap_filter,
+ jclass klass,
+ jobject initial_object,
+ const jvmtiHeapCallbacks* callbacks,
+ const void* user_data) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_tag_objects);
+ HeapUtil heap_util(ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table.get());
+ return heap_util.FollowReferences(env,
+ heap_filter,
+ klass,
+ initial_object,
+ callbacks,
+ user_data);
+ }
+
+ static jvmtiError IterateThroughHeap(jvmtiEnv* env,
+ jint heap_filter,
+ jclass klass,
+ const jvmtiHeapCallbacks* callbacks,
+ const void* user_data) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_tag_objects);
+ HeapUtil heap_util(ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table.get());
+ return heap_util.IterateThroughHeap(env, heap_filter, klass, callbacks, user_data);
+ }
+
+ static jvmtiError GetTag(jvmtiEnv* env, jobject object, jlong* tag_ptr) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_tag_objects);
+
+ JNIEnv* jni_env = GetJniEnv(env);
+ if (jni_env == nullptr) {
+ return ERR(INTERNAL);
+ }
+
+ art::ScopedObjectAccess soa(jni_env);
+ art::ObjPtr<art::mirror::Object> obj = soa.Decode<art::mirror::Object>(object);
+ if (!ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table->GetTag(obj.Ptr(), tag_ptr)) {
+ *tag_ptr = 0;
+ }
+
+ return ERR(NONE);
+ }
+
+ static jvmtiError SetTag(jvmtiEnv* env, jobject object, jlong tag) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_tag_objects);
+
+ if (object == nullptr) {
+ return ERR(NULL_POINTER);
+ }
+
+ JNIEnv* jni_env = GetJniEnv(env);
+ if (jni_env == nullptr) {
+ return ERR(INTERNAL);
+ }
+
+ art::ScopedObjectAccess soa(jni_env);
+ art::ObjPtr<art::mirror::Object> obj = soa.Decode<art::mirror::Object>(object);
+ ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table->Set(obj.Ptr(), tag);
+
+ return ERR(NONE);
+ }
+
+ static jvmtiError GetObjectsWithTags(jvmtiEnv* env,
+ jint tag_count,
+ const jlong* tags,
+ jint* count_ptr,
+ jobject** object_result_ptr,
+ jlong** tag_result_ptr) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_tag_objects);
+
+ JNIEnv* jni_env = GetJniEnv(env);
+ if (jni_env == nullptr) {
+ return ERR(INTERNAL);
+ }
+
+ art::ScopedObjectAccess soa(jni_env);
+ return ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table->GetTaggedObjects(env,
+ tag_count,
+ tags,
+ count_ptr,
+ object_result_ptr,
+ tag_result_ptr);
+ }
+
+ static jvmtiError ForceGarbageCollection(jvmtiEnv* env) {
+ ENSURE_VALID_ENV(env);
+ return HeapUtil::ForceGarbageCollection(env);
+ }
+
+ static jvmtiError IterateOverObjectsReachableFromObject(
+ jvmtiEnv* env,
+ jobject object ATTRIBUTE_UNUSED,
+ jvmtiObjectReferenceCallback object_reference_callback ATTRIBUTE_UNUSED,
+ const void* user_data ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_tag_objects);
+ return ERR(NOT_IMPLEMENTED);
+ }
+
+ static jvmtiError IterateOverReachableObjects(
+ jvmtiEnv* env,
+ jvmtiHeapRootCallback heap_root_callback ATTRIBUTE_UNUSED,
+ jvmtiStackReferenceCallback stack_ref_callback ATTRIBUTE_UNUSED,
+ jvmtiObjectReferenceCallback object_ref_callback ATTRIBUTE_UNUSED,
+ const void* user_data ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_tag_objects);
+ return ERR(NOT_IMPLEMENTED);
+ }
+
+ static jvmtiError IterateOverHeap(jvmtiEnv* env,
+ jvmtiHeapObjectFilter object_filter ATTRIBUTE_UNUSED,
+ jvmtiHeapObjectCallback heap_object_callback ATTRIBUTE_UNUSED,
+ const void* user_data ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_tag_objects);
+ return ERR(NOT_IMPLEMENTED);
+ }
+
+ static jvmtiError IterateOverInstancesOfClass(
+ jvmtiEnv* env,
+ jclass klass ATTRIBUTE_UNUSED,
+ jvmtiHeapObjectFilter object_filter ATTRIBUTE_UNUSED,
+ jvmtiHeapObjectCallback heap_object_callback ATTRIBUTE_UNUSED,
+ const void* user_data ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_tag_objects);
+ return ERR(NOT_IMPLEMENTED);
+ }
+
+ static jvmtiError GetLocalObject(jvmtiEnv* env,
+ jthread thread,
+ jint depth,
+ jint slot,
+ jobject* value_ptr) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_access_local_variables);
+ return MethodUtil::GetLocalVariable(env, thread, depth, slot, value_ptr);
+ }
+
+ static jvmtiError GetLocalInstance(jvmtiEnv* env,
+ jthread thread,
+ jint depth,
+ jobject* value_ptr) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_access_local_variables);
+ return MethodUtil::GetLocalInstance(env, thread, depth, value_ptr);
+ }
+
+ static jvmtiError GetLocalInt(jvmtiEnv* env,
+ jthread thread,
+ jint depth,
+ jint slot,
+ jint* value_ptr) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_access_local_variables);
+ return MethodUtil::GetLocalVariable(env, thread, depth, slot, value_ptr);
+ }
+
+ static jvmtiError GetLocalLong(jvmtiEnv* env,
+ jthread thread,
+ jint depth,
+ jint slot,
+ jlong* value_ptr) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_access_local_variables);
+ return MethodUtil::GetLocalVariable(env, thread, depth, slot, value_ptr);
+ }
+
+ static jvmtiError GetLocalFloat(jvmtiEnv* env,
+ jthread thread,
+ jint depth,
+ jint slot,
+ jfloat* value_ptr) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_access_local_variables);
+ return MethodUtil::GetLocalVariable(env, thread, depth, slot, value_ptr);
+ }
+
+ static jvmtiError GetLocalDouble(jvmtiEnv* env,
+ jthread thread,
+ jint depth,
+ jint slot,
+ jdouble* value_ptr) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_access_local_variables);
+ return MethodUtil::GetLocalVariable(env, thread, depth, slot, value_ptr);
+ }
+
+ static jvmtiError SetLocalObject(jvmtiEnv* env,
+ jthread thread,
+ jint depth,
+ jint slot,
+ jobject value) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_access_local_variables);
+ return MethodUtil::SetLocalVariable(env, thread, depth, slot, value);
+ }
+
+ static jvmtiError SetLocalInt(jvmtiEnv* env,
+ jthread thread,
+ jint depth,
+ jint slot,
+ jint value) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_access_local_variables);
+ return MethodUtil::SetLocalVariable(env, thread, depth, slot, value);
+ }
+
+ static jvmtiError SetLocalLong(jvmtiEnv* env,
+ jthread thread,
+ jint depth,
+ jint slot,
+ jlong value) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_access_local_variables);
+ return MethodUtil::SetLocalVariable(env, thread, depth, slot, value);
+ }
+
+ static jvmtiError SetLocalFloat(jvmtiEnv* env,
+ jthread thread,
+ jint depth,
+ jint slot,
+ jfloat value) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_access_local_variables);
+ return MethodUtil::SetLocalVariable(env, thread, depth, slot, value);
+ }
+
+ static jvmtiError SetLocalDouble(jvmtiEnv* env,
+ jthread thread,
+ jint depth,
+ jint slot,
+ jdouble value) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_access_local_variables);
+ return MethodUtil::SetLocalVariable(env, thread, depth, slot, value);
+ }
+
+
+ static jvmtiError SetBreakpoint(jvmtiEnv* env, jmethodID method, jlocation location) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_generate_breakpoint_events);
+ return BreakpointUtil::SetBreakpoint(env, method, location);
+ }
+
+ static jvmtiError ClearBreakpoint(jvmtiEnv* env, jmethodID method, jlocation location) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_generate_breakpoint_events);
+ return BreakpointUtil::ClearBreakpoint(env, method, location);
+ }
+
+ static jvmtiError SetFieldAccessWatch(jvmtiEnv* env, jclass klass, jfieldID field) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_generate_field_access_events);
+ return FieldUtil::SetFieldAccessWatch(env, klass, field);
+ }
+
+ static jvmtiError ClearFieldAccessWatch(jvmtiEnv* env, jclass klass, jfieldID field) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_generate_field_access_events);
+ return FieldUtil::ClearFieldAccessWatch(env, klass, field);
+ }
+
+ static jvmtiError SetFieldModificationWatch(jvmtiEnv* env, jclass klass, jfieldID field) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_generate_field_modification_events);
+ return FieldUtil::SetFieldModificationWatch(env, klass, field);
+ }
+
+ static jvmtiError ClearFieldModificationWatch(jvmtiEnv* env, jclass klass, jfieldID field) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_generate_field_modification_events);
+ return FieldUtil::ClearFieldModificationWatch(env, klass, field);
+ }
+
+ static jvmtiError GetLoadedClasses(jvmtiEnv* env, jint* class_count_ptr, jclass** classes_ptr) {
+ ENSURE_VALID_ENV(env);
+ HeapUtil heap_util(ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table.get());
+ return heap_util.GetLoadedClasses(env, class_count_ptr, classes_ptr);
+ }
+
+ static jvmtiError GetClassLoaderClasses(jvmtiEnv* env,
+ jobject initiating_loader,
+ jint* class_count_ptr,
+ jclass** classes_ptr) {
+ ENSURE_VALID_ENV(env);
+ return ClassUtil::GetClassLoaderClasses(env, initiating_loader, class_count_ptr, classes_ptr);
+ }
+
+ static jvmtiError GetClassSignature(jvmtiEnv* env,
+ jclass klass,
+ char** signature_ptr,
+ char** generic_ptr) {
+ ENSURE_VALID_ENV(env);
+ return ClassUtil::GetClassSignature(env, klass, signature_ptr, generic_ptr);
+ }
+
+ static jvmtiError GetClassStatus(jvmtiEnv* env, jclass klass, jint* status_ptr) {
+ ENSURE_VALID_ENV(env);
+ return ClassUtil::GetClassStatus(env, klass, status_ptr);
+ }
+
+ static jvmtiError GetSourceFileName(jvmtiEnv* env, jclass klass, char** source_name_ptr) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_get_source_file_name);
+ return ClassUtil::GetSourceFileName(env, klass, source_name_ptr);
+ }
+
+ static jvmtiError GetClassModifiers(jvmtiEnv* env, jclass klass, jint* modifiers_ptr) {
+ ENSURE_VALID_ENV(env);
+ return ClassUtil::GetClassModifiers(env, klass, modifiers_ptr);
+ }
+
+ static jvmtiError GetClassMethods(jvmtiEnv* env,
+ jclass klass,
+ jint* method_count_ptr,
+ jmethodID** methods_ptr) {
+ ENSURE_VALID_ENV(env);
+ return ClassUtil::GetClassMethods(env, klass, method_count_ptr, methods_ptr);
+ }
+
+ static jvmtiError GetClassFields(jvmtiEnv* env,
+ jclass klass,
+ jint* field_count_ptr,
+ jfieldID** fields_ptr) {
+ ENSURE_VALID_ENV(env);
+ return ClassUtil::GetClassFields(env, klass, field_count_ptr, fields_ptr);
+ }
+
+ static jvmtiError GetImplementedInterfaces(jvmtiEnv* env,
+ jclass klass,
+ jint* interface_count_ptr,
+ jclass** interfaces_ptr) {
+ ENSURE_VALID_ENV(env);
+ return ClassUtil::GetImplementedInterfaces(env, klass, interface_count_ptr, interfaces_ptr);
+ }
+
+ static jvmtiError GetClassVersionNumbers(jvmtiEnv* env,
+ jclass klass,
+ jint* minor_version_ptr,
+ jint* major_version_ptr) {
+ ENSURE_VALID_ENV(env);
+ return ClassUtil::GetClassVersionNumbers(env, klass, minor_version_ptr, major_version_ptr);
+ }
+
+ static jvmtiError GetConstantPool(jvmtiEnv* env,
+ jclass klass ATTRIBUTE_UNUSED,
+ jint* constant_pool_count_ptr ATTRIBUTE_UNUSED,
+ jint* constant_pool_byte_count_ptr ATTRIBUTE_UNUSED,
+ unsigned char** constant_pool_bytes_ptr ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_get_constant_pool);
+ return ERR(NOT_IMPLEMENTED);
+ }
+
+ static jvmtiError IsInterface(jvmtiEnv* env, jclass klass, jboolean* is_interface_ptr) {
+ ENSURE_VALID_ENV(env);
+ return ClassUtil::IsInterface(env, klass, is_interface_ptr);
+ }
+
+ static jvmtiError IsArrayClass(jvmtiEnv* env,
+ jclass klass,
+ jboolean* is_array_class_ptr) {
+ ENSURE_VALID_ENV(env);
+ return ClassUtil::IsArrayClass(env, klass, is_array_class_ptr);
+ }
+
+ static jvmtiError IsModifiableClass(jvmtiEnv* env,
+ jclass klass,
+ jboolean* is_modifiable_class_ptr) {
+ ENSURE_VALID_ENV(env);
+ return Redefiner::IsModifiableClass(env, klass, is_modifiable_class_ptr);
+ }
+
+ static jvmtiError GetClassLoader(jvmtiEnv* env, jclass klass, jobject* classloader_ptr) {
+ ENSURE_VALID_ENV(env);
+ return ClassUtil::GetClassLoader(env, klass, classloader_ptr);
+ }
+
+ static jvmtiError GetSourceDebugExtension(jvmtiEnv* env,
+ jclass klass,
+ char** source_debug_extension_ptr) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_get_source_debug_extension);
+ return ClassUtil::GetSourceDebugExtension(env, klass, source_debug_extension_ptr);
+ }
+
+ static jvmtiError RetransformClasses(jvmtiEnv* env, jint class_count, const jclass* classes) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_retransform_classes);
+ std::string error_msg;
+ jvmtiError res = Transformer::RetransformClasses(ArtJvmTiEnv::AsArtJvmTiEnv(env),
+ &gEventHandler,
+ art::Runtime::Current(),
+ art::Thread::Current(),
+ class_count,
+ classes,
+ &error_msg);
+ if (res != OK) {
+ LOG(WARNING) << "FAILURE TO RETRANFORM " << error_msg;
+ }
+ return res;
+ }
+
+ static jvmtiError RedefineClasses(jvmtiEnv* env,
+ jint class_count,
+ const jvmtiClassDefinition* class_definitions) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_redefine_classes);
+ std::string error_msg;
+ jvmtiError res = Redefiner::RedefineClasses(ArtJvmTiEnv::AsArtJvmTiEnv(env),
+ &gEventHandler,
+ art::Runtime::Current(),
+ art::Thread::Current(),
+ class_count,
+ class_definitions,
+ &error_msg);
+ if (res != OK) {
+ LOG(WARNING) << "FAILURE TO REDEFINE " << error_msg;
+ }
+ return res;
+ }
+
+ static jvmtiError GetObjectSize(jvmtiEnv* env, jobject object, jlong* size_ptr) {
+ ENSURE_VALID_ENV(env);
+ return ObjectUtil::GetObjectSize(env, object, size_ptr);
+ }
+
+ static jvmtiError GetObjectHashCode(jvmtiEnv* env, jobject object, jint* hash_code_ptr) {
+ ENSURE_VALID_ENV(env);
+ return ObjectUtil::GetObjectHashCode(env, object, hash_code_ptr);
+ }
+
+ static jvmtiError GetObjectMonitorUsage(jvmtiEnv* env,
+ jobject object ATTRIBUTE_UNUSED,
+ jvmtiMonitorUsage* info_ptr ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_get_monitor_info);
+ return ERR(NOT_IMPLEMENTED);
+ }
+
+ static jvmtiError GetFieldName(jvmtiEnv* env,
+ jclass klass,
+ jfieldID field,
+ char** name_ptr,
+ char** signature_ptr,
+ char** generic_ptr) {
+ ENSURE_VALID_ENV(env);
+ return FieldUtil::GetFieldName(env, klass, field, name_ptr, signature_ptr, generic_ptr);
+ }
+
+ static jvmtiError GetFieldDeclaringClass(jvmtiEnv* env,
+ jclass klass,
+ jfieldID field,
+ jclass* declaring_class_ptr) {
+ ENSURE_VALID_ENV(env);
+ return FieldUtil::GetFieldDeclaringClass(env, klass, field, declaring_class_ptr);
+ }
+
+ static jvmtiError GetFieldModifiers(jvmtiEnv* env,
+ jclass klass,
+ jfieldID field,
+ jint* modifiers_ptr) {
+ ENSURE_VALID_ENV(env);
+ return FieldUtil::GetFieldModifiers(env, klass, field, modifiers_ptr);
+ }
+
+ static jvmtiError IsFieldSynthetic(jvmtiEnv* env,
+ jclass klass,
+ jfieldID field,
+ jboolean* is_synthetic_ptr) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_get_synthetic_attribute);
+ return FieldUtil::IsFieldSynthetic(env, klass, field, is_synthetic_ptr);
+ }
+
+ static jvmtiError GetMethodName(jvmtiEnv* env,
+ jmethodID method,
+ char** name_ptr,
+ char** signature_ptr,
+ char** generic_ptr) {
+ ENSURE_VALID_ENV(env);
+ return MethodUtil::GetMethodName(env, method, name_ptr, signature_ptr, generic_ptr);
+ }
+
+ static jvmtiError GetMethodDeclaringClass(jvmtiEnv* env,
+ jmethodID method,
+ jclass* declaring_class_ptr) {
+ ENSURE_VALID_ENV(env);
+ return MethodUtil::GetMethodDeclaringClass(env, method, declaring_class_ptr);
+ }
+
+ static jvmtiError GetMethodModifiers(jvmtiEnv* env,
+ jmethodID method,
+ jint* modifiers_ptr) {
+ ENSURE_VALID_ENV(env);
+ return MethodUtil::GetMethodModifiers(env, method, modifiers_ptr);
+ }
+
+ static jvmtiError GetMaxLocals(jvmtiEnv* env,
+ jmethodID method,
+ jint* max_ptr) {
+ ENSURE_VALID_ENV(env);
+ return MethodUtil::GetMaxLocals(env, method, max_ptr);
+ }
+
+ static jvmtiError GetArgumentsSize(jvmtiEnv* env,
+ jmethodID method,
+ jint* size_ptr) {
+ ENSURE_VALID_ENV(env);
+ return MethodUtil::GetArgumentsSize(env, method, size_ptr);
+ }
+
+ static jvmtiError GetLineNumberTable(jvmtiEnv* env,
+ jmethodID method,
+ jint* entry_count_ptr,
+ jvmtiLineNumberEntry** table_ptr) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_get_line_numbers);
+ return MethodUtil::GetLineNumberTable(env, method, entry_count_ptr, table_ptr);
+ }
+
+ static jvmtiError GetMethodLocation(jvmtiEnv* env,
+ jmethodID method,
+ jlocation* start_location_ptr,
+ jlocation* end_location_ptr) {
+ ENSURE_VALID_ENV(env);
+ return MethodUtil::GetMethodLocation(env, method, start_location_ptr, end_location_ptr);
+ }
+
+ static jvmtiError GetLocalVariableTable(jvmtiEnv* env,
+ jmethodID method,
+ jint* entry_count_ptr,
+ jvmtiLocalVariableEntry** table_ptr) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_access_local_variables);
+ return MethodUtil::GetLocalVariableTable(env, method, entry_count_ptr, table_ptr);
+ }
+
+ static jvmtiError GetBytecodes(jvmtiEnv* env,
+ jmethodID method,
+ jint* bytecode_count_ptr,
+ unsigned char** bytecodes_ptr) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_get_bytecodes);
+ return MethodUtil::GetBytecodes(env, method, bytecode_count_ptr, bytecodes_ptr);
+ }
+
+ static jvmtiError IsMethodNative(jvmtiEnv* env, jmethodID method, jboolean* is_native_ptr) {
+ ENSURE_VALID_ENV(env);
+ return MethodUtil::IsMethodNative(env, method, is_native_ptr);
+ }
+
+ static jvmtiError IsMethodSynthetic(jvmtiEnv* env, jmethodID method, jboolean* is_synthetic_ptr) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_get_synthetic_attribute);
+ return MethodUtil::IsMethodSynthetic(env, method, is_synthetic_ptr);
+ }
+
+ static jvmtiError IsMethodObsolete(jvmtiEnv* env, jmethodID method, jboolean* is_obsolete_ptr) {
+ ENSURE_VALID_ENV(env);
+ return MethodUtil::IsMethodObsolete(env, method, is_obsolete_ptr);
+ }
+
+ static jvmtiError SetNativeMethodPrefix(jvmtiEnv* env, const char* prefix ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_set_native_method_prefix);
+ return ERR(NOT_IMPLEMENTED);
+ }
+
+ static jvmtiError SetNativeMethodPrefixes(jvmtiEnv* env,
+ jint prefix_count ATTRIBUTE_UNUSED,
+ char** prefixes ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_set_native_method_prefix);
+ return ERR(NOT_IMPLEMENTED);
+ }
+
+ static jvmtiError CreateRawMonitor(jvmtiEnv* env, const char* name, jrawMonitorID* monitor_ptr) {
+ ENSURE_VALID_ENV(env);
+ return MonitorUtil::CreateRawMonitor(env, name, monitor_ptr);
+ }
+
+ static jvmtiError DestroyRawMonitor(jvmtiEnv* env, jrawMonitorID monitor) {
+ ENSURE_VALID_ENV(env);
+ return MonitorUtil::DestroyRawMonitor(env, monitor);
+ }
+
+ static jvmtiError RawMonitorEnter(jvmtiEnv* env, jrawMonitorID monitor) {
+ ENSURE_VALID_ENV(env);
+ return MonitorUtil::RawMonitorEnter(env, monitor);
+ }
+
+ static jvmtiError RawMonitorExit(jvmtiEnv* env, jrawMonitorID monitor) {
+ ENSURE_VALID_ENV(env);
+ return MonitorUtil::RawMonitorExit(env, monitor);
+ }
+
+ static jvmtiError RawMonitorWait(jvmtiEnv* env, jrawMonitorID monitor, jlong millis) {
+ ENSURE_VALID_ENV(env);
+ return MonitorUtil::RawMonitorWait(env, monitor, millis);
+ }
+
+ static jvmtiError RawMonitorNotify(jvmtiEnv* env, jrawMonitorID monitor) {
+ ENSURE_VALID_ENV(env);
+ return MonitorUtil::RawMonitorNotify(env, monitor);
+ }
+
+ static jvmtiError RawMonitorNotifyAll(jvmtiEnv* env, jrawMonitorID monitor) {
+ ENSURE_VALID_ENV(env);
+ return MonitorUtil::RawMonitorNotifyAll(env, monitor);
+ }
+
+ static jvmtiError SetJNIFunctionTable(jvmtiEnv* env, const jniNativeInterface* function_table) {
+ ENSURE_VALID_ENV(env);
+ return JNIUtil::SetJNIFunctionTable(env, function_table);
+ }
+
+ static jvmtiError GetJNIFunctionTable(jvmtiEnv* env, jniNativeInterface** function_table) {
+ ENSURE_VALID_ENV(env);
+ return JNIUtil::GetJNIFunctionTable(env, function_table);
+ }
+
+ // TODO: This will require locking, so that an agent can't remove callbacks when we're dispatching
+ // an event.
+ static jvmtiError SetEventCallbacks(jvmtiEnv* env,
+ const jvmtiEventCallbacks* callbacks,
+ jint size_of_callbacks) {
+ ENSURE_VALID_ENV(env);
+ if (size_of_callbacks < 0) {
+ return ERR(ILLEGAL_ARGUMENT);
+ }
+
+ if (callbacks == nullptr) {
+ ArtJvmTiEnv::AsArtJvmTiEnv(env)->event_callbacks.reset();
+ return ERR(NONE);
+ }
+
+ std::unique_ptr<jvmtiEventCallbacks> tmp(new jvmtiEventCallbacks());
+ memset(tmp.get(), 0, sizeof(jvmtiEventCallbacks));
+ size_t copy_size = std::min(sizeof(jvmtiEventCallbacks),
+ static_cast<size_t>(size_of_callbacks));
+ copy_size = art::RoundDown(copy_size, sizeof(void*));
+ memcpy(tmp.get(), callbacks, copy_size);
+
+ ArtJvmTiEnv::AsArtJvmTiEnv(env)->event_callbacks = std::move(tmp);
+
+ return ERR(NONE);
+ }
+
+ static jvmtiError SetEventNotificationMode(jvmtiEnv* env,
+ jvmtiEventMode mode,
+ jvmtiEvent event_type,
+ jthread event_thread,
+ ...) {
+ ENSURE_VALID_ENV(env);
+ art::Thread* art_thread = nullptr;
+ if (event_thread != nullptr) {
+ // TODO: Need non-aborting call here, to return JVMTI_ERROR_INVALID_THREAD.
+ art::ScopedObjectAccess soa(art::Thread::Current());
+ art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_);
+ art_thread = art::Thread::FromManagedThread(soa, event_thread);
+
+ if (art_thread == nullptr || // The thread hasn't been started or is already dead.
+ art_thread->IsStillStarting()) {
+ // TODO: We may want to let the EventHandler know, so it could clean up masks, potentially.
+ return ERR(THREAD_NOT_ALIVE);
+ }
+ }
+
+ ArtJvmTiEnv* art_env = ArtJvmTiEnv::AsArtJvmTiEnv(env);
+ return gEventHandler.SetEvent(art_env, art_thread, GetArtJvmtiEvent(art_env, event_type), mode);
+ }
+
+ static jvmtiError GenerateEvents(jvmtiEnv* env,
+ jvmtiEvent event_type ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
+ return OK;
+ }
+
+ static jvmtiError GetExtensionFunctions(jvmtiEnv* env,
+ jint* extension_count_ptr,
+ jvmtiExtensionFunctionInfo** extensions) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_NON_NULL(extension_count_ptr);
+ ENSURE_NON_NULL(extensions);
+
+ std::vector<jvmtiExtensionFunctionInfo> ext_vector;
+
+ // Holders for allocated values.
+ std::vector<JvmtiUniquePtr<char[]>> char_buffers;
+ std::vector<JvmtiUniquePtr<jvmtiParamInfo[]>> param_buffers;
+ std::vector<JvmtiUniquePtr<jvmtiError[]>> error_buffers;
+
+ // Add a helper struct that takes an arbitrary const char*. add_extension will use Allocate
+ // appropriately.
+ struct CParamInfo {
+ const char* name;
+ jvmtiParamKind kind;
+ jvmtiParamTypes base_type;
+ jboolean null_ok;
+ };
+
+ auto add_extension = [&](jvmtiExtensionFunction func,
+ const char* id,
+ const char* short_description,
+ jint param_count,
+ const std::vector<CParamInfo>& params,
+ jint error_count,
+ const std::vector<jvmtiError>& errors) {
+ jvmtiExtensionFunctionInfo func_info;
+ jvmtiError error;
+
+ func_info.func = func;
+
+ JvmtiUniquePtr<char[]> id_ptr = CopyString(env, id, &error);
+ if (id_ptr == nullptr) {
+ return error;
+ }
+ func_info.id = id_ptr.get();
+ char_buffers.push_back(std::move(id_ptr));
+
+ JvmtiUniquePtr<char[]> descr = CopyString(env, short_description, &error);
+ if (descr == nullptr) {
+ return error;
+ }
+ func_info.short_description = descr.get();
+ char_buffers.push_back(std::move(descr));
+
+ func_info.param_count = param_count;
+ if (param_count > 0) {
+ JvmtiUniquePtr<jvmtiParamInfo[]> params_ptr =
+ AllocJvmtiUniquePtr<jvmtiParamInfo[]>(env, param_count, &error);
+ if (params_ptr == nullptr) {
+ return error;
+ }
+ func_info.params = params_ptr.get();
+ param_buffers.push_back(std::move(params_ptr));
+
+ for (jint i = 0; i != param_count; ++i) {
+ JvmtiUniquePtr<char[]> param_name = CopyString(env, params[i].name, &error);
+ if (param_name == nullptr) {
+ return error;
+ }
+ func_info.params[i].name = param_name.get();
+ char_buffers.push_back(std::move(param_name));
+
+ func_info.params[i].kind = params[i].kind;
+ func_info.params[i].base_type = params[i].base_type;
+ func_info.params[i].null_ok = params[i].null_ok;
+ }
+ } else {
+ func_info.params = nullptr;
+ }
+
+ func_info.error_count = error_count;
+ if (error_count > 0) {
+ JvmtiUniquePtr<jvmtiError[]> errors_ptr =
+ AllocJvmtiUniquePtr<jvmtiError[]>(env, error_count, &error);
+ if (errors_ptr == nullptr) {
+ return error;
+ }
+ func_info.errors = errors_ptr.get();
+ error_buffers.push_back(std::move(errors_ptr));
+
+ for (jint i = 0; i != error_count; ++i) {
+ func_info.errors[i] = errors[i];
+ }
+ } else {
+ func_info.errors = nullptr;
+ }
+
+ ext_vector.push_back(func_info);
+
+ return ERR(NONE);
+ };
+
+ jvmtiError error;
+
+ // Heap extensions.
+ error = add_extension(
+ reinterpret_cast<jvmtiExtensionFunction>(HeapExtensions::GetObjectHeapId),
+ "com.android.art.heap.get_object_heap_id",
+ "Retrieve the heap id of the the object tagged with the given argument. An "
+ "arbitrary object is chosen if multiple objects exist with the same tag.",
+ 2,
+ { // NOLINT [whitespace/braces] [4]
+ { "tag", JVMTI_KIND_IN, JVMTI_TYPE_JLONG, false},
+ { "heap_id", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false}
+ },
+ 1,
+ { JVMTI_ERROR_NOT_FOUND });
+ if (error != ERR(NONE)) {
+ return error;
+ }
+
+ error = add_extension(
+ reinterpret_cast<jvmtiExtensionFunction>(HeapExtensions::GetHeapName),
+ "com.android.art.heap.get_heap_name",
+ "Retrieve the name of the heap with the given id.",
+ 2,
+ { // NOLINT [whitespace/braces] [4]
+ { "heap_id", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false},
+ { "heap_name", JVMTI_KIND_ALLOC_BUF, JVMTI_TYPE_CCHAR, false}
+ },
+ 1,
+ { JVMTI_ERROR_ILLEGAL_ARGUMENT });
+ if (error != ERR(NONE)) {
+ return error;
+ }
+
+ error = add_extension(
+ reinterpret_cast<jvmtiExtensionFunction>(HeapExtensions::IterateThroughHeapExt),
+ "com.android.art.heap.iterate_through_heap_ext",
+ "Iterate through a heap. This is equivalent to the standard IterateThroughHeap function,"
+ " except for additionally passing the heap id of the current object. The jvmtiHeapCallbacks"
+ " structure is reused, with the callbacks field overloaded to a signature of "
+ "jint (*)(jlong, jlong, jlong*, jint length, void*, jint).",
+ 4,
+ { // NOLINT [whitespace/braces] [4]
+ { "heap_filter", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false},
+ { "klass", JVMTI_KIND_IN, JVMTI_TYPE_JCLASS, true},
+ { "callbacks", JVMTI_KIND_IN_PTR, JVMTI_TYPE_CVOID, false},
+ { "user_data", JVMTI_KIND_IN_PTR, JVMTI_TYPE_CVOID, true}
+ },
+ 3,
+ { // NOLINT [whitespace/braces] [4]
+ JVMTI_ERROR_MUST_POSSESS_CAPABILITY,
+ JVMTI_ERROR_INVALID_CLASS,
+ JVMTI_ERROR_NULL_POINTER
+ });
+ if (error != ERR(NONE)) {
+ return error;
+ }
+
+ error = add_extension(
+ reinterpret_cast<jvmtiExtensionFunction>(AllocUtil::GetGlobalJvmtiAllocationState),
+ "com.android.art.alloc.get_global_jvmti_allocation_state",
+ "Returns the total amount of memory currently allocated by all jvmtiEnvs through the"
+ " 'Allocate' jvmti function. This does not include any memory that has been deallocated"
+ " through the 'Deallocate' function. This number is approximate and might not correspond"
+ " exactly to the sum of the sizes of all not freed allocations.",
+ 1,
+ { // NOLINT [whitespace/braces] [4]
+ { "currently_allocated", JVMTI_KIND_OUT, JVMTI_TYPE_JLONG, false},
+ },
+ 1,
+ { ERR(NULL_POINTER) });
+ if (error != ERR(NONE)) {
+ return error;
+ }
+
+ // Copy into output buffer.
+
+ *extension_count_ptr = ext_vector.size();
+ JvmtiUniquePtr<jvmtiExtensionFunctionInfo[]> out_data =
+ AllocJvmtiUniquePtr<jvmtiExtensionFunctionInfo[]>(env, ext_vector.size(), &error);
+ if (out_data == nullptr) {
+ return error;
+ }
+ memcpy(out_data.get(),
+ ext_vector.data(),
+ ext_vector.size() * sizeof(jvmtiExtensionFunctionInfo));
+ *extensions = out_data.release();
+
+ // Release all the buffer holders, we're OK now.
+ for (auto& holder : char_buffers) {
+ holder.release();
+ }
+ for (auto& holder : param_buffers) {
+ holder.release();
+ }
+ for (auto& holder : error_buffers) {
+ holder.release();
+ }
+
+ return ERR(NONE);
+ }
+
+ static jvmtiError GetExtensionEvents(jvmtiEnv* env,
+ jint* extension_count_ptr,
+ jvmtiExtensionEventInfo** extensions) {
+ ENSURE_VALID_ENV(env);
+ // We do not have any extension events.
+ *extension_count_ptr = 0;
+ *extensions = nullptr;
+
+ return ERR(NONE);
+ }
+
+ static jvmtiError SetExtensionEventCallback(jvmtiEnv* env,
+ jint extension_event_index ATTRIBUTE_UNUSED,
+ jvmtiExtensionEvent callback ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
+ // We do not have any extension events, so any call is illegal.
+ return ERR(ILLEGAL_ARGUMENT);
+ }
+
+ static jvmtiError GetPotentialCapabilities(jvmtiEnv* env, jvmtiCapabilities* capabilities_ptr) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_NON_NULL(capabilities_ptr);
+ *capabilities_ptr = kPotentialCapabilities;
+ return OK;
+ }
+
+ static jvmtiError AddCapabilities(jvmtiEnv* env, const jvmtiCapabilities* capabilities_ptr) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_NON_NULL(capabilities_ptr);
+ ArtJvmTiEnv* art_env = static_cast<ArtJvmTiEnv*>(env);
+ jvmtiError ret = OK;
+ jvmtiCapabilities changed = {};
+ jvmtiCapabilities potential_capabilities = {};
+ ret = env->GetPotentialCapabilities(&potential_capabilities);
+ if (ret != OK) {
+ return ret;
+ }
+#define ADD_CAPABILITY(e) \
+ do { \
+ if (capabilities_ptr->e == 1) { \
+ if (potential_capabilities.e == 1) { \
+ if (art_env->capabilities.e != 1) { \
+ art_env->capabilities.e = 1; \
+ changed.e = 1; \
+ }\
+ } else { \
+ ret = ERR(NOT_AVAILABLE); \
+ } \
+ } \
+ } while (false)
+
+ ADD_CAPABILITY(can_tag_objects);
+ ADD_CAPABILITY(can_generate_field_modification_events);
+ ADD_CAPABILITY(can_generate_field_access_events);
+ ADD_CAPABILITY(can_get_bytecodes);
+ ADD_CAPABILITY(can_get_synthetic_attribute);
+ ADD_CAPABILITY(can_get_owned_monitor_info);
+ ADD_CAPABILITY(can_get_current_contended_monitor);
+ ADD_CAPABILITY(can_get_monitor_info);
+ ADD_CAPABILITY(can_pop_frame);
+ ADD_CAPABILITY(can_redefine_classes);
+ ADD_CAPABILITY(can_signal_thread);
+ ADD_CAPABILITY(can_get_source_file_name);
+ ADD_CAPABILITY(can_get_line_numbers);
+ ADD_CAPABILITY(can_get_source_debug_extension);
+ ADD_CAPABILITY(can_access_local_variables);
+ ADD_CAPABILITY(can_maintain_original_method_order);
+ ADD_CAPABILITY(can_generate_single_step_events);
+ ADD_CAPABILITY(can_generate_exception_events);
+ ADD_CAPABILITY(can_generate_frame_pop_events);
+ ADD_CAPABILITY(can_generate_breakpoint_events);
+ ADD_CAPABILITY(can_suspend);
+ ADD_CAPABILITY(can_redefine_any_class);
+ ADD_CAPABILITY(can_get_current_thread_cpu_time);
+ ADD_CAPABILITY(can_get_thread_cpu_time);
+ ADD_CAPABILITY(can_generate_method_entry_events);
+ ADD_CAPABILITY(can_generate_method_exit_events);
+ ADD_CAPABILITY(can_generate_all_class_hook_events);
+ ADD_CAPABILITY(can_generate_compiled_method_load_events);
+ ADD_CAPABILITY(can_generate_monitor_events);
+ ADD_CAPABILITY(can_generate_vm_object_alloc_events);
+ ADD_CAPABILITY(can_generate_native_method_bind_events);
+ ADD_CAPABILITY(can_generate_garbage_collection_events);
+ ADD_CAPABILITY(can_generate_object_free_events);
+ ADD_CAPABILITY(can_force_early_return);
+ ADD_CAPABILITY(can_get_owned_monitor_stack_depth_info);
+ ADD_CAPABILITY(can_get_constant_pool);
+ ADD_CAPABILITY(can_set_native_method_prefix);
+ ADD_CAPABILITY(can_retransform_classes);
+ ADD_CAPABILITY(can_retransform_any_class);
+ ADD_CAPABILITY(can_generate_resource_exhaustion_heap_events);
+ ADD_CAPABILITY(can_generate_resource_exhaustion_threads_events);
+#undef ADD_CAPABILITY
+ gEventHandler.HandleChangedCapabilities(ArtJvmTiEnv::AsArtJvmTiEnv(env),
+ changed,
+ /*added*/true);
+ return ret;
+ }
+
+ static jvmtiError RelinquishCapabilities(jvmtiEnv* env,
+ const jvmtiCapabilities* capabilities_ptr) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_NON_NULL(capabilities_ptr);
+ ArtJvmTiEnv* art_env = reinterpret_cast<ArtJvmTiEnv*>(env);
+ jvmtiCapabilities changed = {};
+#define DEL_CAPABILITY(e) \
+ do { \
+ if (capabilities_ptr->e == 1) { \
+ if (art_env->capabilities.e == 1) { \
+ art_env->capabilities.e = 0;\
+ changed.e = 1; \
+ } \
+ } \
+ } while (false)
+
+ DEL_CAPABILITY(can_tag_objects);
+ DEL_CAPABILITY(can_generate_field_modification_events);
+ DEL_CAPABILITY(can_generate_field_access_events);
+ DEL_CAPABILITY(can_get_bytecodes);
+ DEL_CAPABILITY(can_get_synthetic_attribute);
+ DEL_CAPABILITY(can_get_owned_monitor_info);
+ DEL_CAPABILITY(can_get_current_contended_monitor);
+ DEL_CAPABILITY(can_get_monitor_info);
+ DEL_CAPABILITY(can_pop_frame);
+ DEL_CAPABILITY(can_redefine_classes);
+ DEL_CAPABILITY(can_signal_thread);
+ DEL_CAPABILITY(can_get_source_file_name);
+ DEL_CAPABILITY(can_get_line_numbers);
+ DEL_CAPABILITY(can_get_source_debug_extension);
+ DEL_CAPABILITY(can_access_local_variables);
+ DEL_CAPABILITY(can_maintain_original_method_order);
+ DEL_CAPABILITY(can_generate_single_step_events);
+ DEL_CAPABILITY(can_generate_exception_events);
+ DEL_CAPABILITY(can_generate_frame_pop_events);
+ DEL_CAPABILITY(can_generate_breakpoint_events);
+ DEL_CAPABILITY(can_suspend);
+ DEL_CAPABILITY(can_redefine_any_class);
+ DEL_CAPABILITY(can_get_current_thread_cpu_time);
+ DEL_CAPABILITY(can_get_thread_cpu_time);
+ DEL_CAPABILITY(can_generate_method_entry_events);
+ DEL_CAPABILITY(can_generate_method_exit_events);
+ DEL_CAPABILITY(can_generate_all_class_hook_events);
+ DEL_CAPABILITY(can_generate_compiled_method_load_events);
+ DEL_CAPABILITY(can_generate_monitor_events);
+ DEL_CAPABILITY(can_generate_vm_object_alloc_events);
+ DEL_CAPABILITY(can_generate_native_method_bind_events);
+ DEL_CAPABILITY(can_generate_garbage_collection_events);
+ DEL_CAPABILITY(can_generate_object_free_events);
+ DEL_CAPABILITY(can_force_early_return);
+ DEL_CAPABILITY(can_get_owned_monitor_stack_depth_info);
+ DEL_CAPABILITY(can_get_constant_pool);
+ DEL_CAPABILITY(can_set_native_method_prefix);
+ DEL_CAPABILITY(can_retransform_classes);
+ DEL_CAPABILITY(can_retransform_any_class);
+ DEL_CAPABILITY(can_generate_resource_exhaustion_heap_events);
+ DEL_CAPABILITY(can_generate_resource_exhaustion_threads_events);
+#undef DEL_CAPABILITY
+ gEventHandler.HandleChangedCapabilities(ArtJvmTiEnv::AsArtJvmTiEnv(env),
+ changed,
+ /*added*/false);
+ return OK;
+ }
+
+ static jvmtiError GetCapabilities(jvmtiEnv* env, jvmtiCapabilities* capabilities_ptr) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_NON_NULL(capabilities_ptr);
+ ArtJvmTiEnv* artenv = reinterpret_cast<ArtJvmTiEnv*>(env);
+ *capabilities_ptr = artenv->capabilities;
+ return OK;
+ }
+
+ static jvmtiError GetCurrentThreadCpuTimerInfo(jvmtiEnv* env,
+ jvmtiTimerInfo* info_ptr ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_get_current_thread_cpu_time);
+ return ERR(NOT_IMPLEMENTED);
+ }
+
+ static jvmtiError GetCurrentThreadCpuTime(jvmtiEnv* env, jlong* nanos_ptr ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_get_current_thread_cpu_time);
+ return ERR(NOT_IMPLEMENTED);
+ }
+
+ static jvmtiError GetThreadCpuTimerInfo(jvmtiEnv* env,
+ jvmtiTimerInfo* info_ptr ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_get_thread_cpu_time);
+ return ERR(NOT_IMPLEMENTED);
+ }
+
+ static jvmtiError GetThreadCpuTime(jvmtiEnv* env,
+ jthread thread ATTRIBUTE_UNUSED,
+ jlong* nanos_ptr ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
+ ENSURE_HAS_CAP(env, can_get_thread_cpu_time);
+ return ERR(NOT_IMPLEMENTED);
+ }
+
+ static jvmtiError GetTimerInfo(jvmtiEnv* env, jvmtiTimerInfo* info_ptr) {
+ ENSURE_VALID_ENV(env);
+ return TimerUtil::GetTimerInfo(env, info_ptr);
+ }
+
+ static jvmtiError GetTime(jvmtiEnv* env, jlong* nanos_ptr) {
+ ENSURE_VALID_ENV(env);
+ return TimerUtil::GetTime(env, nanos_ptr);
+ }
+
+ static jvmtiError GetAvailableProcessors(jvmtiEnv* env, jint* processor_count_ptr) {
+ ENSURE_VALID_ENV(env);
+ return TimerUtil::GetAvailableProcessors(env, processor_count_ptr);
+ }
+
+ static jvmtiError AddToBootstrapClassLoaderSearch(jvmtiEnv* env, const char* segment) {
+ ENSURE_VALID_ENV(env);
+ return SearchUtil::AddToBootstrapClassLoaderSearch(env, segment);
+ }
+
+ static jvmtiError AddToSystemClassLoaderSearch(jvmtiEnv* env, const char* segment) {
+ ENSURE_VALID_ENV(env);
+ return SearchUtil::AddToSystemClassLoaderSearch(env, segment);
+ }
+
+ static jvmtiError GetSystemProperties(jvmtiEnv* env, jint* count_ptr, char*** property_ptr) {
+ ENSURE_VALID_ENV(env);
+ return PropertiesUtil::GetSystemProperties(env, count_ptr, property_ptr);
+ }
+
+ static jvmtiError GetSystemProperty(jvmtiEnv* env, const char* property, char** value_ptr) {
+ ENSURE_VALID_ENV(env);
+ return PropertiesUtil::GetSystemProperty(env, property, value_ptr);
+ }
+
+ static jvmtiError SetSystemProperty(jvmtiEnv* env, const char* property, const char* value) {
+ ENSURE_VALID_ENV(env);
+ return PropertiesUtil::SetSystemProperty(env, property, value);
+ }
+
+ static jvmtiError GetPhase(jvmtiEnv* env, jvmtiPhase* phase_ptr) {
+ ENSURE_VALID_ENV(env);
+ return PhaseUtil::GetPhase(env, phase_ptr);
+ }
+
+ static jvmtiError DisposeEnvironment(jvmtiEnv* env) {
+ ENSURE_VALID_ENV(env);
+ ArtJvmTiEnv* tienv = ArtJvmTiEnv::AsArtJvmTiEnv(env);
+ gEventHandler.RemoveArtJvmTiEnv(tienv);
+ art::Runtime::Current()->RemoveSystemWeakHolder(tienv->object_tag_table.get());
+ ThreadUtil::RemoveEnvironment(tienv);
+ delete tienv;
+ return OK;
+ }
+
+ static jvmtiError SetEnvironmentLocalStorage(jvmtiEnv* env, const void* data) {
+ ENSURE_VALID_ENV(env);
+ reinterpret_cast<ArtJvmTiEnv*>(env)->local_data = const_cast<void*>(data);
+ return OK;
+ }
+
+ static jvmtiError GetEnvironmentLocalStorage(jvmtiEnv* env, void** data_ptr) {
+ ENSURE_VALID_ENV(env);
+ *data_ptr = reinterpret_cast<ArtJvmTiEnv*>(env)->local_data;
+ return OK;
+ }
+
+ static jvmtiError GetVersionNumber(jvmtiEnv* env, jint* version_ptr) {
+ ENSURE_VALID_ENV(env);
+ *version_ptr = JVMTI_VERSION;
+ return OK;
+ }
+
+ static jvmtiError GetErrorName(jvmtiEnv* env, jvmtiError error, char** name_ptr) {
+ ENSURE_NON_NULL(name_ptr);
+ auto copy_fn = [&](const char* name_cstr) {
+ jvmtiError res;
+ JvmtiUniquePtr<char[]> copy = CopyString(env, name_cstr, &res);
+ if (copy == nullptr) {
+ *name_ptr = nullptr;
+ return res;
+ } else {
+ *name_ptr = copy.release();
+ return OK;
+ }
+ };
+ switch (error) {
+#define ERROR_CASE(e) case (JVMTI_ERROR_ ## e) : \
+ return copy_fn("JVMTI_ERROR_"#e);
+ ERROR_CASE(NONE);
+ ERROR_CASE(INVALID_THREAD);
+ ERROR_CASE(INVALID_THREAD_GROUP);
+ ERROR_CASE(INVALID_PRIORITY);
+ ERROR_CASE(THREAD_NOT_SUSPENDED);
+ ERROR_CASE(THREAD_SUSPENDED);
+ ERROR_CASE(THREAD_NOT_ALIVE);
+ ERROR_CASE(INVALID_OBJECT);
+ ERROR_CASE(INVALID_CLASS);
+ ERROR_CASE(CLASS_NOT_PREPARED);
+ ERROR_CASE(INVALID_METHODID);
+ ERROR_CASE(INVALID_LOCATION);
+ ERROR_CASE(INVALID_FIELDID);
+ ERROR_CASE(NO_MORE_FRAMES);
+ ERROR_CASE(OPAQUE_FRAME);
+ ERROR_CASE(TYPE_MISMATCH);
+ ERROR_CASE(INVALID_SLOT);
+ ERROR_CASE(DUPLICATE);
+ ERROR_CASE(NOT_FOUND);
+ ERROR_CASE(INVALID_MONITOR);
+ ERROR_CASE(NOT_MONITOR_OWNER);
+ ERROR_CASE(INTERRUPT);
+ ERROR_CASE(INVALID_CLASS_FORMAT);
+ ERROR_CASE(CIRCULAR_CLASS_DEFINITION);
+ ERROR_CASE(FAILS_VERIFICATION);
+ ERROR_CASE(UNSUPPORTED_REDEFINITION_METHOD_ADDED);
+ ERROR_CASE(UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED);
+ ERROR_CASE(INVALID_TYPESTATE);
+ ERROR_CASE(UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED);
+ ERROR_CASE(UNSUPPORTED_REDEFINITION_METHOD_DELETED);
+ ERROR_CASE(UNSUPPORTED_VERSION);
+ ERROR_CASE(NAMES_DONT_MATCH);
+ ERROR_CASE(UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED);
+ ERROR_CASE(UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED);
+ ERROR_CASE(UNMODIFIABLE_CLASS);
+ ERROR_CASE(NOT_AVAILABLE);
+ ERROR_CASE(MUST_POSSESS_CAPABILITY);
+ ERROR_CASE(NULL_POINTER);
+ ERROR_CASE(ABSENT_INFORMATION);
+ ERROR_CASE(INVALID_EVENT_TYPE);
+ ERROR_CASE(ILLEGAL_ARGUMENT);
+ ERROR_CASE(NATIVE_METHOD);
+ ERROR_CASE(CLASS_LOADER_UNSUPPORTED);
+ ERROR_CASE(OUT_OF_MEMORY);
+ ERROR_CASE(ACCESS_DENIED);
+ ERROR_CASE(WRONG_PHASE);
+ ERROR_CASE(INTERNAL);
+ ERROR_CASE(UNATTACHED_THREAD);
+ ERROR_CASE(INVALID_ENVIRONMENT);
+#undef ERROR_CASE
+ }
+
+ return ERR(ILLEGAL_ARGUMENT);
+ }
+
+ static jvmtiError SetVerboseFlag(jvmtiEnv* env,
+ jvmtiVerboseFlag flag,
+ jboolean value) {
+ ENSURE_VALID_ENV(env);
+ if (flag == jvmtiVerboseFlag::JVMTI_VERBOSE_OTHER) {
+ // OTHER is special, as it's 0, so can't do a bit check.
+ bool val = (value == JNI_TRUE) ? true : false;
+
+ art::gLogVerbosity.collector = val;
+ art::gLogVerbosity.compiler = val;
+ art::gLogVerbosity.deopt = val;
+ art::gLogVerbosity.heap = val;
+ art::gLogVerbosity.jdwp = val;
+ art::gLogVerbosity.jit = val;
+ art::gLogVerbosity.monitor = val;
+ art::gLogVerbosity.oat = val;
+ art::gLogVerbosity.profiler = val;
+ art::gLogVerbosity.signals = val;
+ art::gLogVerbosity.simulator = val;
+ art::gLogVerbosity.startup = val;
+ art::gLogVerbosity.third_party_jni = val;
+ art::gLogVerbosity.threads = val;
+ art::gLogVerbosity.verifier = val;
+ art::gLogVerbosity.image = val;
+
+ // Note: can't switch systrace_lock_logging. That requires changing entrypoints.
+
+ art::gLogVerbosity.agents = val;
+ } else {
+ // Spec isn't clear whether "flag" is a mask or supposed to be single. We implement the mask
+ // semantics.
+ constexpr std::underlying_type<jvmtiVerboseFlag>::type kMask =
+ jvmtiVerboseFlag::JVMTI_VERBOSE_GC |
+ jvmtiVerboseFlag::JVMTI_VERBOSE_CLASS |
+ jvmtiVerboseFlag::JVMTI_VERBOSE_JNI;
+ if ((flag & ~kMask) != 0) {
+ return ERR(ILLEGAL_ARGUMENT);
+ }
+
+ bool val = (value == JNI_TRUE) ? true : false;
+
+ if ((flag & jvmtiVerboseFlag::JVMTI_VERBOSE_GC) != 0) {
+ art::gLogVerbosity.gc = val;
+ }
+
+ if ((flag & jvmtiVerboseFlag::JVMTI_VERBOSE_CLASS) != 0) {
+ art::gLogVerbosity.class_linker = val;
+ }
+
+ if ((flag & jvmtiVerboseFlag::JVMTI_VERBOSE_JNI) != 0) {
+ art::gLogVerbosity.jni = val;
+ }
+ }
+
+ return ERR(NONE);
+ }
+
+ static jvmtiError GetJLocationFormat(jvmtiEnv* env, jvmtiJlocationFormat* format_ptr) {
+ ENSURE_VALID_ENV(env);
+ // Report BCI as jlocation format. We report dex bytecode indices.
+ if (format_ptr == nullptr) {
+ return ERR(NULL_POINTER);
+ }
+ *format_ptr = jvmtiJlocationFormat::JVMTI_JLOCATION_JVMBCI;
+ return ERR(NONE);
+ }
+};
+
+static bool IsJvmtiVersion(jint version) {
+ return version == JVMTI_VERSION_1 ||
+ version == JVMTI_VERSION_1_0 ||
+ version == JVMTI_VERSION_1_1 ||
+ version == JVMTI_VERSION_1_2 ||
+ version == JVMTI_VERSION;
+}
+
+extern const jvmtiInterface_1 gJvmtiInterface;
+
+ArtJvmTiEnv::ArtJvmTiEnv(art::JavaVMExt* runtime, EventHandler* event_handler)
+ : art_vm(runtime),
+ local_data(nullptr),
+ capabilities() {
+ object_tag_table = std::unique_ptr<ObjectTagTable>(new ObjectTagTable(event_handler, this));
+ functions = &gJvmtiInterface;
+}
+
+// Creates a jvmtiEnv and returns it with the art::ti::Env that is associated with it. new_art_ti
+// is a pointer to the uninitialized memory for an art::ti::Env.
+static void CreateArtJvmTiEnv(art::JavaVMExt* vm, /*out*/void** new_jvmtiEnv) {
+ struct ArtJvmTiEnv* env = new ArtJvmTiEnv(vm, &gEventHandler);
+ *new_jvmtiEnv = env;
+
+ gEventHandler.RegisterArtJvmTiEnv(env);
+
+ art::Runtime::Current()->AddSystemWeakHolder(
+ ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table.get());
+}
+
+// A hook that the runtime uses to allow plugins to handle GetEnv calls. It returns true and
+// places the return value in 'env' if this library can handle the GetEnv request. Otherwise
+// returns false and does not modify the 'env' pointer.
+static jint GetEnvHandler(art::JavaVMExt* vm, /*out*/void** env, jint version) {
+ if (IsJvmtiVersion(version)) {
+ CreateArtJvmTiEnv(vm, env);
+ return JNI_OK;
+ } else {
+ printf("version 0x%x is not valid!", version);
+ return JNI_EVERSION;
+ }
+}
+
+// The plugin initialization function. This adds the jvmti environment.
+extern "C" bool ArtPlugin_Initialize() {
+ art::Runtime* runtime = art::Runtime::Current();
+
+ if (runtime->IsStarted()) {
+ PhaseUtil::SetToLive();
+ } else {
+ PhaseUtil::SetToOnLoad();
+ }
+ PhaseUtil::Register(&gEventHandler);
+ ThreadUtil::Register(&gEventHandler);
+ ClassUtil::Register(&gEventHandler);
+ DumpUtil::Register(&gEventHandler);
+ MethodUtil::Register(&gEventHandler);
+ SearchUtil::Register();
+ HeapUtil::Register();
+
+ runtime->GetJavaVM()->AddEnvironmentHook(GetEnvHandler);
+
+ return true;
+}
+
+extern "C" bool ArtPlugin_Deinitialize() {
+ gEventHandler.Shutdown();
+ PhaseUtil::Unregister();
+ ThreadUtil::Unregister();
+ ClassUtil::Unregister();
+ DumpUtil::Unregister();
+ MethodUtil::Unregister();
+ SearchUtil::Unregister();
+ HeapUtil::Unregister();
+
+ return true;
+}
+
+// The actual struct holding all of the entrypoints into the jvmti interface.
+const jvmtiInterface_1 gJvmtiInterface = {
+ nullptr, // reserved1
+ JvmtiFunctions::SetEventNotificationMode,
+ nullptr, // reserved3
+ JvmtiFunctions::GetAllThreads,
+ JvmtiFunctions::SuspendThread,
+ JvmtiFunctions::ResumeThread,
+ JvmtiFunctions::StopThread,
+ JvmtiFunctions::InterruptThread,
+ JvmtiFunctions::GetThreadInfo,
+ JvmtiFunctions::GetOwnedMonitorInfo, // 10
+ JvmtiFunctions::GetCurrentContendedMonitor,
+ JvmtiFunctions::RunAgentThread,
+ JvmtiFunctions::GetTopThreadGroups,
+ JvmtiFunctions::GetThreadGroupInfo,
+ JvmtiFunctions::GetThreadGroupChildren,
+ JvmtiFunctions::GetFrameCount,
+ JvmtiFunctions::GetThreadState,
+ JvmtiFunctions::GetCurrentThread,
+ JvmtiFunctions::GetFrameLocation,
+ JvmtiFunctions::NotifyFramePop, // 20
+ JvmtiFunctions::GetLocalObject,
+ JvmtiFunctions::GetLocalInt,
+ JvmtiFunctions::GetLocalLong,
+ JvmtiFunctions::GetLocalFloat,
+ JvmtiFunctions::GetLocalDouble,
+ JvmtiFunctions::SetLocalObject,
+ JvmtiFunctions::SetLocalInt,
+ JvmtiFunctions::SetLocalLong,
+ JvmtiFunctions::SetLocalFloat,
+ JvmtiFunctions::SetLocalDouble, // 30
+ JvmtiFunctions::CreateRawMonitor,
+ JvmtiFunctions::DestroyRawMonitor,
+ JvmtiFunctions::RawMonitorEnter,
+ JvmtiFunctions::RawMonitorExit,
+ JvmtiFunctions::RawMonitorWait,
+ JvmtiFunctions::RawMonitorNotify,
+ JvmtiFunctions::RawMonitorNotifyAll,
+ JvmtiFunctions::SetBreakpoint,
+ JvmtiFunctions::ClearBreakpoint,
+ nullptr, // reserved40
+ JvmtiFunctions::SetFieldAccessWatch,
+ JvmtiFunctions::ClearFieldAccessWatch,
+ JvmtiFunctions::SetFieldModificationWatch,
+ JvmtiFunctions::ClearFieldModificationWatch,
+ JvmtiFunctions::IsModifiableClass,
+ JvmtiFunctions::Allocate,
+ JvmtiFunctions::Deallocate,
+ JvmtiFunctions::GetClassSignature,
+ JvmtiFunctions::GetClassStatus,
+ JvmtiFunctions::GetSourceFileName, // 50
+ JvmtiFunctions::GetClassModifiers,
+ JvmtiFunctions::GetClassMethods,
+ JvmtiFunctions::GetClassFields,
+ JvmtiFunctions::GetImplementedInterfaces,
+ JvmtiFunctions::IsInterface,
+ JvmtiFunctions::IsArrayClass,
+ JvmtiFunctions::GetClassLoader,
+ JvmtiFunctions::GetObjectHashCode,
+ JvmtiFunctions::GetObjectMonitorUsage,
+ JvmtiFunctions::GetFieldName, // 60
+ JvmtiFunctions::GetFieldDeclaringClass,
+ JvmtiFunctions::GetFieldModifiers,
+ JvmtiFunctions::IsFieldSynthetic,
+ JvmtiFunctions::GetMethodName,
+ JvmtiFunctions::GetMethodDeclaringClass,
+ JvmtiFunctions::GetMethodModifiers,
+ nullptr, // reserved67
+ JvmtiFunctions::GetMaxLocals,
+ JvmtiFunctions::GetArgumentsSize,
+ JvmtiFunctions::GetLineNumberTable, // 70
+ JvmtiFunctions::GetMethodLocation,
+ JvmtiFunctions::GetLocalVariableTable,
+ JvmtiFunctions::SetNativeMethodPrefix,
+ JvmtiFunctions::SetNativeMethodPrefixes,
+ JvmtiFunctions::GetBytecodes,
+ JvmtiFunctions::IsMethodNative,
+ JvmtiFunctions::IsMethodSynthetic,
+ JvmtiFunctions::GetLoadedClasses,
+ JvmtiFunctions::GetClassLoaderClasses,
+ JvmtiFunctions::PopFrame, // 80
+ JvmtiFunctions::ForceEarlyReturnObject,
+ JvmtiFunctions::ForceEarlyReturnInt,
+ JvmtiFunctions::ForceEarlyReturnLong,
+ JvmtiFunctions::ForceEarlyReturnFloat,
+ JvmtiFunctions::ForceEarlyReturnDouble,
+ JvmtiFunctions::ForceEarlyReturnVoid,
+ JvmtiFunctions::RedefineClasses,
+ JvmtiFunctions::GetVersionNumber,
+ JvmtiFunctions::GetCapabilities,
+ JvmtiFunctions::GetSourceDebugExtension, // 90
+ JvmtiFunctions::IsMethodObsolete,
+ JvmtiFunctions::SuspendThreadList,
+ JvmtiFunctions::ResumeThreadList,
+ nullptr, // reserved94
+ nullptr, // reserved95
+ nullptr, // reserved96
+ nullptr, // reserved97
+ nullptr, // reserved98
+ nullptr, // reserved99
+ JvmtiFunctions::GetAllStackTraces, // 100
+ JvmtiFunctions::GetThreadListStackTraces,
+ JvmtiFunctions::GetThreadLocalStorage,
+ JvmtiFunctions::SetThreadLocalStorage,
+ JvmtiFunctions::GetStackTrace,
+ nullptr, // reserved105
+ JvmtiFunctions::GetTag,
+ JvmtiFunctions::SetTag,
+ JvmtiFunctions::ForceGarbageCollection,
+ JvmtiFunctions::IterateOverObjectsReachableFromObject,
+ JvmtiFunctions::IterateOverReachableObjects, // 110
+ JvmtiFunctions::IterateOverHeap,
+ JvmtiFunctions::IterateOverInstancesOfClass,
+ nullptr, // reserved113
+ JvmtiFunctions::GetObjectsWithTags,
+ JvmtiFunctions::FollowReferences,
+ JvmtiFunctions::IterateThroughHeap,
+ nullptr, // reserved117
+ nullptr, // reserved118
+ nullptr, // reserved119
+ JvmtiFunctions::SetJNIFunctionTable, // 120
+ JvmtiFunctions::GetJNIFunctionTable,
+ JvmtiFunctions::SetEventCallbacks,
+ JvmtiFunctions::GenerateEvents,
+ JvmtiFunctions::GetExtensionFunctions,
+ JvmtiFunctions::GetExtensionEvents,
+ JvmtiFunctions::SetExtensionEventCallback,
+ JvmtiFunctions::DisposeEnvironment,
+ JvmtiFunctions::GetErrorName,
+ JvmtiFunctions::GetJLocationFormat,
+ JvmtiFunctions::GetSystemProperties, // 130
+ JvmtiFunctions::GetSystemProperty,
+ JvmtiFunctions::SetSystemProperty,
+ JvmtiFunctions::GetPhase,
+ JvmtiFunctions::GetCurrentThreadCpuTimerInfo,
+ JvmtiFunctions::GetCurrentThreadCpuTime,
+ JvmtiFunctions::GetThreadCpuTimerInfo,
+ JvmtiFunctions::GetThreadCpuTime,
+ JvmtiFunctions::GetTimerInfo,
+ JvmtiFunctions::GetTime,
+ JvmtiFunctions::GetPotentialCapabilities, // 140
+ nullptr, // reserved141
+ JvmtiFunctions::AddCapabilities,
+ JvmtiFunctions::RelinquishCapabilities,
+ JvmtiFunctions::GetAvailableProcessors,
+ JvmtiFunctions::GetClassVersionNumbers,
+ JvmtiFunctions::GetConstantPool,
+ JvmtiFunctions::GetEnvironmentLocalStorage,
+ JvmtiFunctions::SetEnvironmentLocalStorage,
+ JvmtiFunctions::AddToBootstrapClassLoaderSearch,
+ JvmtiFunctions::SetVerboseFlag, // 150
+ JvmtiFunctions::AddToSystemClassLoaderSearch,
+ JvmtiFunctions::RetransformClasses,
+ JvmtiFunctions::GetOwnedMonitorStackDepthInfo,
+ JvmtiFunctions::GetObjectSize,
+ JvmtiFunctions::GetLocalInstance,
+};
+
+}; // namespace openjdkjvmti