blob: 450f85e51a8c017bd3df4f0ae6a8705f3da8ee6a [file] [log] [blame]
Andreas Gampe77708d92016-10-07 11:48:21 -07001/* Copyright (C) 2016 The Android Open Source Project
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 *
4 * This file implements interfaces from the file jvmti.h. This implementation
5 * is licensed under the same terms as the file jvmti.h. The
6 * copyright and license information for the file jvmti.h follows.
7 *
8 * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
9 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
10 *
11 * This code is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License version 2 only, as
13 * published by the Free Software Foundation. Oracle designates this
14 * particular file as subject to the "Classpath" exception as provided
15 * by Oracle in the LICENSE file that accompanied this code.
16 *
17 * This code is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * version 2 for more details (a copy is included in the LICENSE file that
21 * accompanied this code).
22 *
23 * You should have received a copy of the GNU General Public License version
24 * 2 along with this work; if not, write to the Free Software Foundation,
25 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
26 *
27 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
28 * or visit www.oracle.com if you need additional information or have any
29 * questions.
30 */
31
Andreas Gampe27fa96c2016-10-07 15:05:24 -070032#include "events-inl.h"
Andreas Gampe77708d92016-10-07 11:48:21 -070033
34#include "art_jvmti.h"
Andreas Gampe27fa96c2016-10-07 15:05:24 -070035#include "base/logging.h"
36#include "gc/allocation_listener.h"
37#include "instrumentation.h"
38#include "jni_env_ext-inl.h"
39#include "mirror/class.h"
40#include "mirror/object.h"
41#include "runtime.h"
42#include "ScopedLocalRef.h"
Andreas Gampe77708d92016-10-07 11:48:21 -070043
44namespace openjdkjvmti {
45
46EventMask& EventMasks::GetEventMask(art::Thread* thread) {
47 if (thread == nullptr) {
48 return global_event_mask;
49 }
50
51 for (auto& pair : thread_event_masks) {
52 const UniqueThread& unique_thread = pair.first;
53 if (unique_thread.first == thread &&
54 unique_thread.second == static_cast<uint32_t>(thread->GetTid())) {
55 return pair.second;
56 }
57 }
58
59 // TODO: Remove old UniqueThread with the same pointer, if exists.
60
61 thread_event_masks.emplace_back(UniqueThread(thread, thread->GetTid()), EventMask());
62 return thread_event_masks.back().second;
63}
64
65EventMask* EventMasks::GetEventMaskOrNull(art::Thread* thread) {
66 if (thread == nullptr) {
67 return &global_event_mask;
68 }
69
70 for (auto& pair : thread_event_masks) {
71 const UniqueThread& unique_thread = pair.first;
72 if (unique_thread.first == thread &&
73 unique_thread.second == static_cast<uint32_t>(thread->GetTid())) {
74 return &pair.second;
75 }
76 }
77
78 return nullptr;
79}
80
81
82void EventMasks::EnableEvent(art::Thread* thread, jvmtiEvent event) {
83 DCHECK(EventMask::EventIsInRange(event));
84 GetEventMask(thread).Set(event);
85 if (thread != nullptr) {
86 unioned_thread_event_mask.Set(event, true);
87 }
88}
89
90void EventMasks::DisableEvent(art::Thread* thread, jvmtiEvent event) {
91 DCHECK(EventMask::EventIsInRange(event));
92 GetEventMask(thread).Set(event, false);
93 if (thread != nullptr) {
94 // Regenerate union for the event.
95 bool union_value = false;
96 for (auto& pair : thread_event_masks) {
97 union_value |= pair.second.Test(event);
98 if (union_value) {
99 break;
100 }
101 }
102 unioned_thread_event_mask.Set(event, union_value);
103 }
104}
105
106void EventHandler::RegisterArtJvmTiEnv(ArtJvmTiEnv* env) {
107 envs.push_back(env);
108}
109
110static bool IsThreadControllable(jvmtiEvent event) {
111 switch (event) {
112 case JVMTI_EVENT_VM_INIT:
113 case JVMTI_EVENT_VM_START:
114 case JVMTI_EVENT_VM_DEATH:
115 case JVMTI_EVENT_THREAD_START:
116 case JVMTI_EVENT_COMPILED_METHOD_LOAD:
117 case JVMTI_EVENT_COMPILED_METHOD_UNLOAD:
118 case JVMTI_EVENT_DYNAMIC_CODE_GENERATED:
119 case JVMTI_EVENT_DATA_DUMP_REQUEST:
120 return false;
121
122 default:
123 return true;
124 }
125}
126
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700127class JvmtiAllocationListener : public art::gc::AllocationListener {
128 public:
129 explicit JvmtiAllocationListener(EventHandler* handler) : handler_(handler) {}
130
Mathieu Chartier9d156d52016-10-06 17:44:26 -0700131 void ObjectAllocated(art::Thread* self, art::ObjPtr<art::mirror::Object>* obj, size_t byte_count)
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700132 REQUIRES_SHARED(art::Locks::mutator_lock_) {
133 DCHECK_EQ(self, art::Thread::Current());
134
135 if (handler_->IsEventEnabledAnywhere(JVMTI_EVENT_VM_OBJECT_ALLOC)) {
Mathieu Chartiera7118042016-10-12 15:45:58 -0700136 art::StackHandleScope<1> hs(self);
137 auto h = hs.NewHandleWrapper(obj);
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700138 // jvmtiEventVMObjectAlloc parameters:
139 // jvmtiEnv *jvmti_env,
140 // JNIEnv* jni_env,
141 // jthread thread,
142 // jobject object,
143 // jclass object_klass,
144 // jlong size
145 art::JNIEnvExt* jni_env = self->GetJniEnv();
146
147 jthread thread_peer;
148 if (self->IsStillStarting()) {
149 thread_peer = nullptr;
150 } else {
151 thread_peer = jni_env->AddLocalReference<jthread>(self->GetPeer());
152 }
153
154 ScopedLocalRef<jthread> thread(jni_env, thread_peer);
155 ScopedLocalRef<jobject> object(
156 jni_env, jni_env->AddLocalReference<jobject>(*obj));
157 ScopedLocalRef<jclass> klass(
Mathieu Chartier9d156d52016-10-06 17:44:26 -0700158 jni_env, jni_env->AddLocalReference<jclass>(obj->Ptr()->GetClass()));
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700159
160 handler_->DispatchEvent(self,
161 JVMTI_EVENT_VM_OBJECT_ALLOC,
162 jni_env,
163 thread.get(),
164 object.get(),
165 klass.get(),
166 byte_count);
167 }
168 }
169
170 private:
171 EventHandler* handler_;
172};
173
174static void SetupObjectAllocationTracking(art::gc::AllocationListener* listener, bool enable) {
175 if (enable) {
176 art::Runtime::Current()->GetHeap()->SetAllocationListener(listener);
177 } else {
178 art::Runtime::Current()->GetHeap()->RemoveAllocationListener();
179 }
180}
181
Andreas Gampe77708d92016-10-07 11:48:21 -0700182// Handle special work for the given event type, if necessary.
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700183void EventHandler::HandleEventType(jvmtiEvent event, bool enable) {
184 if (event == JVMTI_EVENT_VM_OBJECT_ALLOC) {
185 SetupObjectAllocationTracking(alloc_listener_.get(), enable);
186 return;
187 }
Andreas Gampe77708d92016-10-07 11:48:21 -0700188}
189
190jvmtiError EventHandler::SetEvent(ArtJvmTiEnv* env,
191 art::Thread* thread,
192 jvmtiEvent event,
193 jvmtiEventMode mode) {
194 if (thread != nullptr) {
195 art::ThreadState state = thread->GetState();
196 if (state == art::ThreadState::kStarting ||
197 state == art::ThreadState::kTerminated ||
198 thread->IsStillStarting()) {
199 return ERR(THREAD_NOT_ALIVE);
200 }
201 if (!IsThreadControllable(event)) {
202 return ERR(ILLEGAL_ARGUMENT);
203 }
204 }
205
206 // TODO: Capability check.
207
208 if (mode != JVMTI_ENABLE && mode != JVMTI_DISABLE) {
209 return ERR(ILLEGAL_ARGUMENT);
210 }
211
212 if (!EventMask::EventIsInRange(event)) {
213 return ERR(INVALID_EVENT_TYPE);
214 }
215
216 if (mode == JVMTI_ENABLE) {
217 env->event_masks.EnableEvent(thread, event);
218 global_mask.Set(event);
219 } else {
220 DCHECK_EQ(mode, JVMTI_DISABLE);
221
222 env->event_masks.DisableEvent(thread, event);
223
224 // Gotta recompute the global mask.
225 bool union_value = false;
226 for (const ArtJvmTiEnv* stored_env : envs) {
227 union_value |= stored_env->event_masks.global_event_mask.Test(event);
228 union_value |= stored_env->event_masks.unioned_thread_event_mask.Test(event);
229 if (union_value) {
230 break;
231 }
232 }
233 global_mask.Set(event, union_value);
234 }
235
236 // Handle any special work required for the event type.
237 HandleEventType(event, mode == JVMTI_ENABLE);
238
239 return ERR(NONE);
240}
241
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700242EventHandler::EventHandler() {
243 alloc_listener_.reset(new JvmtiAllocationListener(this));
244}
245
246EventHandler::~EventHandler() {
247}
248
Andreas Gampe77708d92016-10-07 11:48:21 -0700249} // namespace openjdkjvmti