summaryrefslogtreecommitdiff
path: root/openjdkjvmti/ti_extension.cc
diff options
context:
space:
mode:
Diffstat (limited to 'openjdkjvmti/ti_extension.cc')
-rw-r--r--openjdkjvmti/ti_extension.cc167
1 files changed, 152 insertions, 15 deletions
diff --git a/openjdkjvmti/ti_extension.cc b/openjdkjvmti/ti_extension.cc
index fbed9640a0..afd0723d0f 100644
--- a/openjdkjvmti/ti_extension.cc
+++ b/openjdkjvmti/ti_extension.cc
@@ -34,8 +34,11 @@
#include "ti_extension.h"
#include "art_jvmti.h"
+#include "events.h"
#include "ti_allocator.h"
+#include "ti_ddms.h"
#include "ti_heap.h"
+#include "thread-inl.h"
namespace openjdkjvmti {
@@ -51,7 +54,7 @@ struct CParamInfo {
JvmtiUniquePtr<char[]> param_name = CopyString(env, name, err);
char* name_ptr = param_name.get();
char_buffers->push_back(std::move(param_name));
- return jvmtiParamInfo { name_ptr, kind, base_type, null_ok }; // NOLINT [whitespace/braces] [4]
+ return jvmtiParamInfo{ name_ptr, kind, base_type, null_ok };
}
};
@@ -143,7 +146,7 @@ jvmtiError ExtensionUtil::GetExtensionFunctions(jvmtiEnv* env,
"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.",
- { // NOLINT [whitespace/braces] [4]
+ {
{ "tag", JVMTI_KIND_IN, JVMTI_TYPE_JLONG, false},
{ "heap_id", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false}
},
@@ -156,7 +159,7 @@ jvmtiError ExtensionUtil::GetExtensionFunctions(jvmtiEnv* env,
reinterpret_cast<jvmtiExtensionFunction>(HeapExtensions::GetHeapName),
"com.android.art.heap.get_heap_name",
"Retrieve the name of the heap with the given id.",
- { // NOLINT [whitespace/braces] [4]
+ {
{ "heap_id", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false},
{ "heap_name", JVMTI_KIND_ALLOC_BUF, JVMTI_TYPE_CCHAR, false}
},
@@ -172,13 +175,13 @@ jvmtiError ExtensionUtil::GetExtensionFunctions(jvmtiEnv* env,
" 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).",
- { // 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}
},
- { // NOLINT [whitespace/braces] [4]
+ {
ERR(MUST_POSSESS_CAPABILITY),
ERR(INVALID_CLASS),
ERR(NULL_POINTER),
@@ -194,7 +197,7 @@ jvmtiError ExtensionUtil::GetExtensionFunctions(jvmtiEnv* env,
" '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.",
- { // NOLINT [whitespace/braces] [4]
+ {
{ "currently_allocated", JVMTI_KIND_OUT, JVMTI_TYPE_JLONG, false},
},
{ ERR(NULL_POINTER) });
@@ -202,6 +205,27 @@ jvmtiError ExtensionUtil::GetExtensionFunctions(jvmtiEnv* env,
return error;
}
+ // DDMS extension
+ error = add_extension(
+ reinterpret_cast<jvmtiExtensionFunction>(DDMSUtil::HandleChunk),
+ "com.android.art.internal.ddm.process_chunk",
+ "Handles a single ddms chunk request and returns a response. The reply data is in the ddms"
+ " chunk format. It returns the processed chunk. This is provided for backwards compatibility"
+ " reasons only. Agents should avoid making use of this extension when possible and instead"
+ " use the other JVMTI entrypoints explicitly.",
+ {
+ { "type_in", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
+ { "length_in", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
+ { "data_in", JVMTI_KIND_IN_BUF, JVMTI_TYPE_JBYTE, false },
+ { "type_out", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false },
+ { "data_len_out", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false },
+ { "data_out", JVMTI_KIND_ALLOC_BUF, JVMTI_TYPE_JBYTE, false }
+ },
+ { ERR(NULL_POINTER), ERR(ILLEGAL_ARGUMENT), ERR(OUT_OF_MEMORY) });
+ if (error != ERR(NONE)) {
+ return error;
+ }
+
// Copy into output buffer.
*extension_count_ptr = ext_vector.size();
@@ -230,20 +254,133 @@ jvmtiError ExtensionUtil::GetExtensionFunctions(jvmtiEnv* env,
}
-jvmtiError ExtensionUtil::GetExtensionEvents(jvmtiEnv* env ATTRIBUTE_UNUSED,
+jvmtiError ExtensionUtil::GetExtensionEvents(jvmtiEnv* env,
jint* extension_count_ptr,
jvmtiExtensionEventInfo** extensions) {
- // We don't have any extension events at the moment.
- *extension_count_ptr = 0;
- *extensions = nullptr;
+ std::vector<jvmtiExtensionEventInfo> ext_vector;
+
+ // Holders for allocated values.
+ std::vector<JvmtiUniquePtr<char[]>> char_buffers;
+ std::vector<JvmtiUniquePtr<jvmtiParamInfo[]>> param_buffers;
+
+ auto add_extension = [&](ArtJvmtiEvent extension_event_index,
+ const char* id,
+ const char* short_description,
+ const std::vector<CParamInfo>& params) {
+ DCHECK(IsExtensionEvent(extension_event_index));
+ jvmtiExtensionEventInfo event_info;
+ jvmtiError error;
+
+ event_info.extension_event_index = static_cast<jint>(extension_event_index);
+
+ JvmtiUniquePtr<char[]> id_ptr = CopyString(env, id, &error);
+ if (id_ptr == nullptr) {
+ return error;
+ }
+ event_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;
+ }
+ event_info.short_description = descr.get();
+ char_buffers.push_back(std::move(descr));
+
+ event_info.param_count = params.size();
+ if (!params.empty()) {
+ JvmtiUniquePtr<jvmtiParamInfo[]> params_ptr =
+ AllocJvmtiUniquePtr<jvmtiParamInfo[]>(env, params.size(), &error);
+ if (params_ptr == nullptr) {
+ return error;
+ }
+ event_info.params = params_ptr.get();
+ param_buffers.push_back(std::move(params_ptr));
+
+ for (jint i = 0; i != event_info.param_count; ++i) {
+ event_info.params[i] = params[i].ToParamInfo(env, &char_buffers, &error);
+ if (error != OK) {
+ return error;
+ }
+ }
+ } else {
+ event_info.params = nullptr;
+ }
+
+ ext_vector.push_back(event_info);
+
+ return ERR(NONE);
+ };
+
+ jvmtiError error;
+ error = add_extension(
+ ArtJvmtiEvent::kDdmPublishChunk,
+ "com.android.art.internal.ddm.publish_chunk",
+ "Called when there is new ddms information that the agent or other clients can use. The"
+ " agent is given the 'type' of the ddms chunk and a 'data_size' byte-buffer in 'data'."
+ " The 'data' pointer is only valid for the duration of the publish_chunk event. The agent"
+ " is responsible for interpreting the information present in the 'data' buffer. This is"
+ " provided for backwards-compatibility support only. Agents should prefer to use relevant"
+ " JVMTI events and functions above listening for this event.",
+ {
+ { "jni_env", JVMTI_KIND_IN_PTR, JVMTI_TYPE_JNIENV, false },
+ { "type", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
+ { "data_size", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
+ { "data", JVMTI_KIND_IN_BUF, JVMTI_TYPE_JBYTE, false },
+ });
+ if (error != OK) {
+ return error;
+ }
+
+ // Copy into output buffer.
+
+ *extension_count_ptr = ext_vector.size();
+ JvmtiUniquePtr<jvmtiExtensionEventInfo[]> out_data =
+ AllocJvmtiUniquePtr<jvmtiExtensionEventInfo[]>(env, ext_vector.size(), &error);
+ if (out_data == nullptr) {
+ return error;
+ }
+ memcpy(out_data.get(),
+ ext_vector.data(),
+ ext_vector.size() * sizeof(jvmtiExtensionEventInfo));
+ *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();
+ }
+
return OK;
}
-jvmtiError ExtensionUtil::SetExtensionEventCallback(jvmtiEnv* env ATTRIBUTE_UNUSED,
- jint extension_event_index ATTRIBUTE_UNUSED,
- jvmtiExtensionEvent callback ATTRIBUTE_UNUSED) {
- // We do not have any extension events, so any call is illegal.
- return ERR(ILLEGAL_ARGUMENT);
+jvmtiError ExtensionUtil::SetExtensionEventCallback(jvmtiEnv* env,
+ jint extension_event_index,
+ jvmtiExtensionEvent callback,
+ EventHandler* event_handler) {
+ if (!IsExtensionEvent(extension_event_index)) {
+ return ERR(ILLEGAL_ARGUMENT);
+ }
+ ArtJvmTiEnv* art_env = ArtJvmTiEnv::AsArtJvmTiEnv(env);
+ jvmtiEventMode mode = callback == nullptr ? JVMTI_DISABLE : JVMTI_ENABLE;
+ // Lock the event_info_mutex_ while we set the event to make sure it isn't lost by a concurrent
+ // change to the normal callbacks.
+ {
+ art::WriterMutexLock lk(art::Thread::Current(), art_env->event_info_mutex_);
+ if (art_env->event_callbacks.get() == nullptr) {
+ art_env->event_callbacks.reset(new ArtJvmtiEventCallbacks());
+ }
+ jvmtiError err = art_env->event_callbacks->Set(extension_event_index, callback);
+ if (err != OK) {
+ return err;
+ }
+ }
+ return event_handler->SetEvent(art_env,
+ /*event_thread*/nullptr,
+ static_cast<ArtJvmtiEvent>(extension_event_index),
+ mode);
}
} // namespace openjdkjvmti