summaryrefslogtreecommitdiff
path: root/openjdkjvmti
diff options
context:
space:
mode:
Diffstat (limited to 'openjdkjvmti')
-rw-r--r--openjdkjvmti/Android.bp1
-rw-r--r--openjdkjvmti/OpenjdkJvmTi.cc19
-rw-r--r--openjdkjvmti/art_jvmti.h2
-rw-r--r--openjdkjvmti/events-inl.h11
-rw-r--r--openjdkjvmti/events.cc75
-rw-r--r--openjdkjvmti/events.h30
-rw-r--r--openjdkjvmti/include/CPPLINT.cfg18
-rw-r--r--openjdkjvmti/jvmti_allocator.h4
-rw-r--r--openjdkjvmti/ti_class.cc2
-rw-r--r--openjdkjvmti/ti_ddms.cc85
-rw-r--r--openjdkjvmti/ti_ddms.h53
-rw-r--r--openjdkjvmti/ti_extension.cc167
-rw-r--r--openjdkjvmti/ti_extension.h5
-rw-r--r--openjdkjvmti/ti_monitor.cc6
14 files changed, 443 insertions, 35 deletions
diff --git a/openjdkjvmti/Android.bp b/openjdkjvmti/Android.bp
index aef4dfc201..9ba7068176 100644
--- a/openjdkjvmti/Android.bp
+++ b/openjdkjvmti/Android.bp
@@ -34,6 +34,7 @@ cc_defaults {
"ti_class.cc",
"ti_class_definition.cc",
"ti_class_loader.cc",
+ "ti_ddms.cc",
"ti_dump.cc",
"ti_extension.cc",
"ti_field.cc",
diff --git a/openjdkjvmti/OpenjdkJvmTi.cc b/openjdkjvmti/OpenjdkJvmTi.cc
index 481492402b..62f723dec1 100644
--- a/openjdkjvmti/OpenjdkJvmTi.cc
+++ b/openjdkjvmti/OpenjdkJvmTi.cc
@@ -1014,14 +1014,21 @@ class JvmtiFunctions {
return ERR(NONE);
}
- std::unique_ptr<jvmtiEventCallbacks> tmp(new jvmtiEventCallbacks());
- memset(tmp.get(), 0, sizeof(jvmtiEventCallbacks));
+ // Lock the event_info_mutex_ while we replace the callbacks.
+ ArtJvmTiEnv* art_env = ArtJvmTiEnv::AsArtJvmTiEnv(env);
+ art::WriterMutexLock lk(art::Thread::Current(), art_env->event_info_mutex_);
+ std::unique_ptr<ArtJvmtiEventCallbacks> tmp(new ArtJvmtiEventCallbacks());
+ // Copy over the extension events.
+ tmp->CopyExtensionsFrom(art_env->event_callbacks.get());
+ // Never overwrite the extension events.
size_t copy_size = std::min(sizeof(jvmtiEventCallbacks),
static_cast<size_t>(size_of_callbacks));
copy_size = art::RoundDown(copy_size, sizeof(void*));
+ // Copy non-extension events.
memcpy(tmp.get(), callbacks, copy_size);
- ArtJvmTiEnv::AsArtJvmTiEnv(env)->event_callbacks = std::move(tmp);
+ // replace the event table.
+ art_env->event_callbacks = std::move(tmp);
return ERR(NONE);
}
@@ -1077,8 +1084,10 @@ class JvmtiFunctions {
jint extension_event_index,
jvmtiExtensionEvent callback) {
ENSURE_VALID_ENV(env);
- // We do not have any extension events, so any call is illegal.
- return ExtensionUtil::SetExtensionEventCallback(env, extension_event_index, callback);
+ return ExtensionUtil::SetExtensionEventCallback(env,
+ extension_event_index,
+ callback,
+ &gEventHandler);
}
static jvmtiError GetPotentialCapabilities(jvmtiEnv* env, jvmtiCapabilities* capabilities_ptr) {
diff --git a/openjdkjvmti/art_jvmti.h b/openjdkjvmti/art_jvmti.h
index 97801e09aa..682b82b5cd 100644
--- a/openjdkjvmti/art_jvmti.h
+++ b/openjdkjvmti/art_jvmti.h
@@ -68,7 +68,7 @@ struct ArtJvmTiEnv : public jvmtiEnv {
jvmtiCapabilities capabilities;
EventMasks event_masks;
- std::unique_ptr<jvmtiEventCallbacks> event_callbacks;
+ std::unique_ptr<ArtJvmtiEventCallbacks> event_callbacks;
// Tagging is specific to the jvmtiEnv.
std::unique_ptr<ObjectTagTable> object_tag_table;
diff --git a/openjdkjvmti/events-inl.h b/openjdkjvmti/events-inl.h
index 7f77f90862..5344e0fbde 100644
--- a/openjdkjvmti/events-inl.h
+++ b/openjdkjvmti/events-inl.h
@@ -80,16 +80,17 @@ namespace impl {
fn(GarbageCollectionStart, ArtJvmtiEvent::kGarbageCollectionStart) \
fn(GarbageCollectionFinish, ArtJvmtiEvent::kGarbageCollectionFinish) \
fn(ObjectFree, ArtJvmtiEvent::kObjectFree) \
- fn(VMObjectAlloc, ArtJvmtiEvent::kVmObjectAlloc)
+ fn(VMObjectAlloc, ArtJvmtiEvent::kVmObjectAlloc) \
+ fn(DdmPublishChunk, ArtJvmtiEvent::kDdmPublishChunk)
template <ArtJvmtiEvent kEvent>
struct EventFnType {
};
-#define EVENT_FN_TYPE(name, enum_name) \
-template <> \
-struct EventFnType<enum_name> { \
- using type = decltype(jvmtiEventCallbacks().name); \
+#define EVENT_FN_TYPE(name, enum_name) \
+template <> \
+struct EventFnType<enum_name> { \
+ using type = decltype(ArtJvmtiEventCallbacks().name); \
};
FORALL_EVENT_TYPES(EVENT_FN_TYPE)
diff --git a/openjdkjvmti/events.cc b/openjdkjvmti/events.cc
index 6a64441a4a..d1d606de48 100644
--- a/openjdkjvmti/events.cc
+++ b/openjdkjvmti/events.cc
@@ -60,6 +60,45 @@
namespace openjdkjvmti {
+void ArtJvmtiEventCallbacks::CopyExtensionsFrom(const ArtJvmtiEventCallbacks* cb) {
+ if (art::kIsDebugBuild) {
+ ArtJvmtiEventCallbacks clean;
+ DCHECK_EQ(memcmp(&clean, this, sizeof(clean)), 0)
+ << "CopyExtensionsFrom called with initialized eventsCallbacks!";
+ }
+ if (cb != nullptr) {
+ memcpy(this, cb, sizeof(*this));
+ } else {
+ memset(this, 0, sizeof(*this));
+ }
+}
+
+jvmtiError ArtJvmtiEventCallbacks::Set(jint index, jvmtiExtensionEvent cb) {
+ switch (index) {
+ case static_cast<jint>(ArtJvmtiEvent::kDdmPublishChunk):
+ DdmPublishChunk = reinterpret_cast<ArtJvmtiEventDdmPublishChunk>(cb);
+ return OK;
+ default:
+ return ERR(ILLEGAL_ARGUMENT);
+ }
+}
+
+
+bool IsExtensionEvent(jint e) {
+ return e >= static_cast<jint>(ArtJvmtiEvent::kMinEventTypeVal) &&
+ e <= static_cast<jint>(ArtJvmtiEvent::kMaxEventTypeVal) &&
+ IsExtensionEvent(static_cast<ArtJvmtiEvent>(e));
+}
+
+bool IsExtensionEvent(ArtJvmtiEvent e) {
+ switch (e) {
+ case ArtJvmtiEvent::kDdmPublishChunk:
+ return true;
+ default:
+ return false;
+ }
+}
+
bool EventMasks::IsEnabledAnywhere(ArtJvmtiEvent event) {
return global_event_mask.Test(event) || unioned_thread_event_mask.Test(event);
}
@@ -213,6 +252,38 @@ static void RunEventCallback(EventHandler* handler,
args...);
}
+static void SetupDdmTracking(art::DdmCallback* listener, bool enable) {
+ art::ScopedObjectAccess soa(art::Thread::Current());
+ if (enable) {
+ art::Runtime::Current()->GetRuntimeCallbacks()->AddDdmCallback(listener);
+ } else {
+ art::Runtime::Current()->GetRuntimeCallbacks()->RemoveDdmCallback(listener);
+ }
+}
+
+class JvmtiDdmChunkListener : public art::DdmCallback {
+ public:
+ explicit JvmtiDdmChunkListener(EventHandler* handler) : handler_(handler) {}
+
+ void DdmPublishChunk(uint32_t type, const art::ArrayRef<const uint8_t>& data)
+ OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ if (handler_->IsEventEnabledAnywhere(ArtJvmtiEvent::kDdmPublishChunk)) {
+ art::Thread* self = art::Thread::Current();
+ handler_->DispatchEvent<ArtJvmtiEvent::kDdmPublishChunk>(
+ self,
+ static_cast<JNIEnv*>(self->GetJniEnv()),
+ static_cast<jint>(type),
+ static_cast<jint>(data.size()),
+ reinterpret_cast<const jbyte*>(data.data()));
+ }
+ }
+
+ private:
+ EventHandler* handler_;
+
+ DISALLOW_COPY_AND_ASSIGN(JvmtiDdmChunkListener);
+};
+
class JvmtiAllocationListener : public art::gc::AllocationListener {
public:
explicit JvmtiAllocationListener(EventHandler* handler) : handler_(handler) {}
@@ -924,6 +995,9 @@ bool EventHandler::OtherMonitorEventsEnabledAnywhere(ArtJvmtiEvent event) {
// Handle special work for the given event type, if necessary.
void EventHandler::HandleEventType(ArtJvmtiEvent event, bool enable) {
switch (event) {
+ case ArtJvmtiEvent::kDdmPublishChunk:
+ SetupDdmTracking(ddm_listener_.get(), enable);
+ return;
case ArtJvmtiEvent::kVmObjectAlloc:
SetupObjectAllocationTracking(alloc_listener_.get(), enable);
return;
@@ -1104,6 +1178,7 @@ void EventHandler::Shutdown() {
EventHandler::EventHandler() {
alloc_listener_.reset(new JvmtiAllocationListener(this));
+ ddm_listener_.reset(new JvmtiDdmChunkListener(this));
gc_pause_listener_.reset(new JvmtiGcPauseListener(this));
method_trace_listener_.reset(new JvmtiMethodTraceListener(this));
monitor_listener_.reset(new JvmtiMonitorListener(this));
diff --git a/openjdkjvmti/events.h b/openjdkjvmti/events.h
index aed24e59f3..a99ed7b212 100644
--- a/openjdkjvmti/events.h
+++ b/openjdkjvmti/events.h
@@ -28,13 +28,14 @@ namespace openjdkjvmti {
struct ArtJvmTiEnv;
class JvmtiAllocationListener;
+class JvmtiDdmChunkListener;
class JvmtiGcPauseListener;
class JvmtiMethodTraceListener;
class JvmtiMonitorListener;
// an enum for ArtEvents. This differs from the JVMTI events only in that we distinguish between
// retransformation capable and incapable loading
-enum class ArtJvmtiEvent {
+enum class ArtJvmtiEvent : jint {
kMinEventTypeVal = JVMTI_MIN_EVENT_TYPE_VAL,
kVmInit = JVMTI_EVENT_VM_INIT,
kVmDeath = JVMTI_EVENT_VM_DEATH,
@@ -68,9 +69,33 @@ enum class ArtJvmtiEvent {
kObjectFree = JVMTI_EVENT_OBJECT_FREE,
kVmObjectAlloc = JVMTI_EVENT_VM_OBJECT_ALLOC,
kClassFileLoadHookRetransformable = JVMTI_MAX_EVENT_TYPE_VAL + 1,
- kMaxEventTypeVal = kClassFileLoadHookRetransformable,
+ kDdmPublishChunk = JVMTI_MAX_EVENT_TYPE_VAL + 2,
+ kMaxEventTypeVal = kDdmPublishChunk,
};
+using ArtJvmtiEventDdmPublishChunk = void (*)(jvmtiEnv *jvmti_env,
+ JNIEnv* jni_env,
+ jint data_type,
+ jint data_len,
+ const jbyte* data);
+
+struct ArtJvmtiEventCallbacks : jvmtiEventCallbacks {
+ ArtJvmtiEventCallbacks() : DdmPublishChunk(nullptr) {
+ memset(this, 0, sizeof(jvmtiEventCallbacks));
+ }
+
+ // Copies extension functions from other callback struct if it exists. There must not have been
+ // any modifications to this struct when it is called.
+ void CopyExtensionsFrom(const ArtJvmtiEventCallbacks* cb);
+
+ jvmtiError Set(jint index, jvmtiExtensionEvent cb);
+
+ ArtJvmtiEventDdmPublishChunk DdmPublishChunk;
+};
+
+bool IsExtensionEvent(jint e);
+bool IsExtensionEvent(ArtJvmtiEvent e);
+
// Convert a jvmtiEvent into a ArtJvmtiEvent
ALWAYS_INLINE static inline ArtJvmtiEvent GetArtJvmtiEvent(ArtJvmTiEnv* env, jvmtiEvent e);
@@ -245,6 +270,7 @@ class EventHandler {
EventMask global_mask;
std::unique_ptr<JvmtiAllocationListener> alloc_listener_;
+ std::unique_ptr<JvmtiDdmChunkListener> ddm_listener_;
std::unique_ptr<JvmtiGcPauseListener> gc_pause_listener_;
std::unique_ptr<JvmtiMethodTraceListener> method_trace_listener_;
std::unique_ptr<JvmtiMonitorListener> monitor_listener_;
diff --git a/openjdkjvmti/include/CPPLINT.cfg b/openjdkjvmti/include/CPPLINT.cfg
new file mode 100644
index 0000000000..3e717a697f
--- /dev/null
+++ b/openjdkjvmti/include/CPPLINT.cfg
@@ -0,0 +1,18 @@
+#
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# External headers, not subject to our lint rules.
+exclude_files=^jvmti[.]h$
diff --git a/openjdkjvmti/jvmti_allocator.h b/openjdkjvmti/jvmti_allocator.h
index e6cbc85170..11af7b67e7 100644
--- a/openjdkjvmti/jvmti_allocator.h
+++ b/openjdkjvmti/jvmti_allocator.h
@@ -58,7 +58,7 @@ class JvmtiAllocator<void> {
JvmtiAllocator() : env_(nullptr) {}
template <typename U>
- JvmtiAllocator(const JvmtiAllocator<U>& other) // NOLINT, implicit
+ JvmtiAllocator(const JvmtiAllocator<U>& other)
: env_(other.env_) {}
JvmtiAllocator(const JvmtiAllocator& other) = default;
@@ -95,7 +95,7 @@ class JvmtiAllocator {
JvmtiAllocator() : env_(nullptr) {}
template <typename U>
- JvmtiAllocator(const JvmtiAllocator<U>& other) // NOLINT, implicit
+ JvmtiAllocator(const JvmtiAllocator<U>& other)
: env_(other.env_) {}
JvmtiAllocator(const JvmtiAllocator& other) = default;
diff --git a/openjdkjvmti/ti_class.cc b/openjdkjvmti/ti_class.cc
index 2c5e5f9ccf..e69c78bab1 100644
--- a/openjdkjvmti/ti_class.cc
+++ b/openjdkjvmti/ti_class.cc
@@ -33,7 +33,7 @@
#include "android-base/stringprintf.h"
-#include <mutex> // NOLINT [build/c++11] [5]
+#include <mutex>
#include <unordered_set>
#include "art_jvmti.h"
diff --git a/openjdkjvmti/ti_ddms.cc b/openjdkjvmti/ti_ddms.cc
new file mode 100644
index 0000000000..500a453f78
--- /dev/null
+++ b/openjdkjvmti/ti_ddms.cc
@@ -0,0 +1,85 @@
+/* Copyright (C) 2017 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 <functional>
+#include <vector>
+
+#include "ti_ddms.h"
+
+#include "art_jvmti.h"
+#include "base/array_ref.h"
+#include "debugger.h"
+#include "scoped_thread_state_change-inl.h"
+#include "thread-inl.h"
+
+namespace openjdkjvmti {
+
+jvmtiError DDMSUtil::HandleChunk(jvmtiEnv* env,
+ jint type_in,
+ jint length_in,
+ const jbyte* data_in,
+ /*out*/jint* type_out,
+ /*out*/jint* data_length_out,
+ /*out*/jbyte** data_out) {
+ constexpr uint32_t kDdmHeaderSize = sizeof(uint32_t) * 2;
+ if (env == nullptr || data_in == nullptr || data_out == nullptr || data_length_out == nullptr) {
+ return ERR(NULL_POINTER);
+ } else if (length_in < static_cast<jint>(kDdmHeaderSize)) {
+ // need to get type and length at least.
+ return ERR(ILLEGAL_ARGUMENT);
+ }
+
+ art::Thread* self = art::Thread::Current();
+ art::ScopedThreadStateChange(self, art::ThreadState::kNative);
+
+ art::ArrayRef<const jbyte> data_arr(data_in, length_in);
+ std::vector<uint8_t> out_data;
+ if (!art::Dbg::DdmHandleChunk(self->GetJniEnv(),
+ type_in,
+ data_arr,
+ /*out*/reinterpret_cast<uint32_t*>(type_out),
+ /*out*/&out_data)) {
+ LOG(WARNING) << "Something went wrong with handling the ddm chunk.";
+ return ERR(INTERNAL);
+ } else {
+ jvmtiError error = OK;
+ JvmtiUniquePtr<jbyte[]> ret = AllocJvmtiUniquePtr<jbyte[]>(env, out_data.size(), &error);
+ if (error != OK) {
+ return error;
+ }
+ memcpy(ret.get(), out_data.data(), out_data.size());
+ *data_out = ret.release();
+ *data_length_out = static_cast<jint>(out_data.size());
+ return OK;
+ }
+}
+
+} // namespace openjdkjvmti
diff --git a/openjdkjvmti/ti_ddms.h b/openjdkjvmti/ti_ddms.h
new file mode 100644
index 0000000000..1ea7548607
--- /dev/null
+++ b/openjdkjvmti/ti_ddms.h
@@ -0,0 +1,53 @@
+/* Copyright (C) 2017 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.
+ */
+
+#ifndef ART_OPENJDKJVMTI_TI_DDMS_H_
+#define ART_OPENJDKJVMTI_TI_DDMS_H_
+
+#include "jni.h"
+#include "jvmti.h"
+
+namespace openjdkjvmti {
+
+class DDMSUtil {
+ public:
+ static jvmtiError HandleChunk(jvmtiEnv* env,
+ jint type_in,
+ jint length_in,
+ const jbyte* data_in,
+ /*out*/ jint* type_out,
+ /*out*/ jint* data_length_out,
+ /*out*/ jbyte** data_out);
+};
+
+} // namespace openjdkjvmti
+
+#endif // ART_OPENJDKJVMTI_TI_DDMS_H_
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
diff --git a/openjdkjvmti/ti_extension.h b/openjdkjvmti/ti_extension.h
index d705ba7f59..18133e98e2 100644
--- a/openjdkjvmti/ti_extension.h
+++ b/openjdkjvmti/ti_extension.h
@@ -37,6 +37,8 @@
namespace openjdkjvmti {
+class EventHandler;
+
class ExtensionUtil {
public:
static jvmtiError GetExtensionFunctions(jvmtiEnv* env,
@@ -49,7 +51,8 @@ class ExtensionUtil {
static jvmtiError SetExtensionEventCallback(jvmtiEnv* env,
jint extension_event_index,
- jvmtiExtensionEvent callback);
+ jvmtiExtensionEvent callback,
+ EventHandler* event_handler);
};
} // namespace openjdkjvmti
diff --git a/openjdkjvmti/ti_monitor.cc b/openjdkjvmti/ti_monitor.cc
index b31e9f239d..7db0566a2e 100644
--- a/openjdkjvmti/ti_monitor.cc
+++ b/openjdkjvmti/ti_monitor.cc
@@ -32,9 +32,9 @@
#include "ti_monitor.h"
#include <atomic>
-#include <chrono> // NOLINT [build/c++11] [5]
-#include <condition_variable> // NOLINT [build/c++11] [5]
-#include <mutex> // NOLINT [build/c++11] [5]
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
#include "art_jvmti.h"
#include "monitor.h"