blob: 66929cf8ab702adfaf74c02606913f63f1cc94ff [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"
Andreas Gampe9b8c5882016-10-21 15:27:46 -070037#include "gc/gc_pause_listener.h"
38#include "gc/heap.h"
Andreas Gampe27fa96c2016-10-07 15:05:24 -070039#include "instrumentation.h"
40#include "jni_env_ext-inl.h"
41#include "mirror/class.h"
42#include "mirror/object.h"
43#include "runtime.h"
44#include "ScopedLocalRef.h"
Andreas Gampec02685c2016-10-17 17:40:27 -070045#include "scoped_thread_state_change-inl.h"
46#include "thread-inl.h"
Andreas Gampe77708d92016-10-07 11:48:21 -070047
48namespace openjdkjvmti {
49
50EventMask& EventMasks::GetEventMask(art::Thread* thread) {
51 if (thread == nullptr) {
52 return global_event_mask;
53 }
54
55 for (auto& pair : thread_event_masks) {
56 const UniqueThread& unique_thread = pair.first;
57 if (unique_thread.first == thread &&
58 unique_thread.second == static_cast<uint32_t>(thread->GetTid())) {
59 return pair.second;
60 }
61 }
62
63 // TODO: Remove old UniqueThread with the same pointer, if exists.
64
65 thread_event_masks.emplace_back(UniqueThread(thread, thread->GetTid()), EventMask());
66 return thread_event_masks.back().second;
67}
68
69EventMask* EventMasks::GetEventMaskOrNull(art::Thread* thread) {
70 if (thread == nullptr) {
71 return &global_event_mask;
72 }
73
74 for (auto& pair : thread_event_masks) {
75 const UniqueThread& unique_thread = pair.first;
76 if (unique_thread.first == thread &&
77 unique_thread.second == static_cast<uint32_t>(thread->GetTid())) {
78 return &pair.second;
79 }
80 }
81
82 return nullptr;
83}
84
85
Alex Light40d87f42017-01-18 10:27:06 -080086void EventMasks::EnableEvent(art::Thread* thread, ArtJvmtiEvent event) {
Andreas Gampe77708d92016-10-07 11:48:21 -070087 DCHECK(EventMask::EventIsInRange(event));
88 GetEventMask(thread).Set(event);
89 if (thread != nullptr) {
90 unioned_thread_event_mask.Set(event, true);
91 }
92}
93
Alex Light40d87f42017-01-18 10:27:06 -080094void EventMasks::DisableEvent(art::Thread* thread, ArtJvmtiEvent event) {
Andreas Gampe77708d92016-10-07 11:48:21 -070095 DCHECK(EventMask::EventIsInRange(event));
96 GetEventMask(thread).Set(event, false);
97 if (thread != nullptr) {
98 // Regenerate union for the event.
99 bool union_value = false;
100 for (auto& pair : thread_event_masks) {
101 union_value |= pair.second.Test(event);
102 if (union_value) {
103 break;
104 }
105 }
106 unioned_thread_event_mask.Set(event, union_value);
107 }
108}
109
110void EventHandler::RegisterArtJvmTiEnv(ArtJvmTiEnv* env) {
111 envs.push_back(env);
112}
113
Alex Light40d87f42017-01-18 10:27:06 -0800114static bool IsThreadControllable(ArtJvmtiEvent event) {
Andreas Gampe77708d92016-10-07 11:48:21 -0700115 switch (event) {
Alex Light40d87f42017-01-18 10:27:06 -0800116 case ArtJvmtiEvent::kVmInit:
117 case ArtJvmtiEvent::kVmStart:
118 case ArtJvmtiEvent::kVmDeath:
119 case ArtJvmtiEvent::kThreadStart:
120 case ArtJvmtiEvent::kCompiledMethodLoad:
121 case ArtJvmtiEvent::kCompiledMethodUnload:
122 case ArtJvmtiEvent::kDynamicCodeGenerated:
123 case ArtJvmtiEvent::kDataDumpRequest:
Andreas Gampe77708d92016-10-07 11:48:21 -0700124 return false;
125
126 default:
127 return true;
128 }
129}
130
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700131class JvmtiAllocationListener : public art::gc::AllocationListener {
132 public:
133 explicit JvmtiAllocationListener(EventHandler* handler) : handler_(handler) {}
134
Mathieu Chartier9d156d52016-10-06 17:44:26 -0700135 void ObjectAllocated(art::Thread* self, art::ObjPtr<art::mirror::Object>* obj, size_t byte_count)
Andreas Gampe9b8c5882016-10-21 15:27:46 -0700136 OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700137 DCHECK_EQ(self, art::Thread::Current());
138
Alex Light40d87f42017-01-18 10:27:06 -0800139 if (handler_->IsEventEnabledAnywhere(ArtJvmtiEvent::kVmObjectAlloc)) {
Mathieu Chartiera7118042016-10-12 15:45:58 -0700140 art::StackHandleScope<1> hs(self);
141 auto h = hs.NewHandleWrapper(obj);
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700142 // jvmtiEventVMObjectAlloc parameters:
143 // jvmtiEnv *jvmti_env,
144 // JNIEnv* jni_env,
145 // jthread thread,
146 // jobject object,
147 // jclass object_klass,
148 // jlong size
149 art::JNIEnvExt* jni_env = self->GetJniEnv();
150
151 jthread thread_peer;
152 if (self->IsStillStarting()) {
153 thread_peer = nullptr;
154 } else {
155 thread_peer = jni_env->AddLocalReference<jthread>(self->GetPeer());
156 }
157
158 ScopedLocalRef<jthread> thread(jni_env, thread_peer);
159 ScopedLocalRef<jobject> object(
160 jni_env, jni_env->AddLocalReference<jobject>(*obj));
161 ScopedLocalRef<jclass> klass(
Mathieu Chartier9d156d52016-10-06 17:44:26 -0700162 jni_env, jni_env->AddLocalReference<jclass>(obj->Ptr()->GetClass()));
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700163
164 handler_->DispatchEvent(self,
Alex Light40d87f42017-01-18 10:27:06 -0800165 ArtJvmtiEvent::kVmObjectAlloc,
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700166 jni_env,
167 thread.get(),
168 object.get(),
169 klass.get(),
170 byte_count);
171 }
172 }
173
174 private:
175 EventHandler* handler_;
176};
177
178static void SetupObjectAllocationTracking(art::gc::AllocationListener* listener, bool enable) {
Andreas Gampec02685c2016-10-17 17:40:27 -0700179 // We must not hold the mutator lock here, but if we're in FastJNI, for example, we might. For
180 // now, do a workaround: (possibly) acquire and release.
181 art::ScopedObjectAccess soa(art::Thread::Current());
182 art::ScopedThreadSuspension sts(soa.Self(), art::ThreadState::kSuspended);
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700183 if (enable) {
184 art::Runtime::Current()->GetHeap()->SetAllocationListener(listener);
185 } else {
186 art::Runtime::Current()->GetHeap()->RemoveAllocationListener();
187 }
188}
189
Andreas Gampe9b8c5882016-10-21 15:27:46 -0700190// Report GC pauses (see spec) as GARBAGE_COLLECTION_START and GARBAGE_COLLECTION_END.
191class JvmtiGcPauseListener : public art::gc::GcPauseListener {
192 public:
193 explicit JvmtiGcPauseListener(EventHandler* handler)
194 : handler_(handler),
195 start_enabled_(false),
196 finish_enabled_(false) {}
197
198 void StartPause() OVERRIDE {
Alex Light40d87f42017-01-18 10:27:06 -0800199 handler_->DispatchEvent(nullptr, ArtJvmtiEvent::kGarbageCollectionStart);
Andreas Gampe9b8c5882016-10-21 15:27:46 -0700200 }
201
202 void EndPause() OVERRIDE {
Alex Light40d87f42017-01-18 10:27:06 -0800203 handler_->DispatchEvent(nullptr, ArtJvmtiEvent::kGarbageCollectionFinish);
Andreas Gampe9b8c5882016-10-21 15:27:46 -0700204 }
205
206 bool IsEnabled() {
207 return start_enabled_ || finish_enabled_;
208 }
209
210 void SetStartEnabled(bool e) {
211 start_enabled_ = e;
212 }
213
214 void SetFinishEnabled(bool e) {
215 finish_enabled_ = e;
216 }
217
218 private:
219 EventHandler* handler_;
220 bool start_enabled_;
221 bool finish_enabled_;
222};
223
Alex Light40d87f42017-01-18 10:27:06 -0800224static void SetupGcPauseTracking(JvmtiGcPauseListener* listener, ArtJvmtiEvent event, bool enable) {
Andreas Gampe9b8c5882016-10-21 15:27:46 -0700225 bool old_state = listener->IsEnabled();
226
Alex Light40d87f42017-01-18 10:27:06 -0800227 if (event == ArtJvmtiEvent::kGarbageCollectionStart) {
Andreas Gampe9b8c5882016-10-21 15:27:46 -0700228 listener->SetStartEnabled(enable);
229 } else {
230 listener->SetFinishEnabled(enable);
231 }
232
233 bool new_state = listener->IsEnabled();
234
235 if (old_state != new_state) {
236 if (new_state) {
237 art::Runtime::Current()->GetHeap()->SetGcPauseListener(listener);
238 } else {
239 art::Runtime::Current()->GetHeap()->RemoveGcPauseListener();
240 }
241 }
242}
243
Andreas Gampe77708d92016-10-07 11:48:21 -0700244// Handle special work for the given event type, if necessary.
Alex Light40d87f42017-01-18 10:27:06 -0800245void EventHandler::HandleEventType(ArtJvmtiEvent event, bool enable) {
Andreas Gampe9b8c5882016-10-21 15:27:46 -0700246 switch (event) {
Alex Light40d87f42017-01-18 10:27:06 -0800247 case ArtJvmtiEvent::kVmObjectAlloc:
Andreas Gampe9b8c5882016-10-21 15:27:46 -0700248 SetupObjectAllocationTracking(alloc_listener_.get(), enable);
249 return;
250
Alex Light40d87f42017-01-18 10:27:06 -0800251 case ArtJvmtiEvent::kGarbageCollectionStart:
252 case ArtJvmtiEvent::kGarbageCollectionFinish:
Andreas Gampe9b8c5882016-10-21 15:27:46 -0700253 SetupGcPauseTracking(gc_pause_listener_.get(), event, enable);
254 return;
255
256 default:
257 break;
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700258 }
Andreas Gampe77708d92016-10-07 11:48:21 -0700259}
260
261jvmtiError EventHandler::SetEvent(ArtJvmTiEnv* env,
262 art::Thread* thread,
Alex Light40d87f42017-01-18 10:27:06 -0800263 ArtJvmtiEvent event,
Andreas Gampe77708d92016-10-07 11:48:21 -0700264 jvmtiEventMode mode) {
265 if (thread != nullptr) {
266 art::ThreadState state = thread->GetState();
267 if (state == art::ThreadState::kStarting ||
268 state == art::ThreadState::kTerminated ||
269 thread->IsStillStarting()) {
270 return ERR(THREAD_NOT_ALIVE);
271 }
272 if (!IsThreadControllable(event)) {
273 return ERR(ILLEGAL_ARGUMENT);
274 }
275 }
276
277 // TODO: Capability check.
278
279 if (mode != JVMTI_ENABLE && mode != JVMTI_DISABLE) {
280 return ERR(ILLEGAL_ARGUMENT);
281 }
282
283 if (!EventMask::EventIsInRange(event)) {
284 return ERR(INVALID_EVENT_TYPE);
285 }
286
Andreas Gampe8b862ff2016-10-17 17:49:59 -0700287 bool old_state = global_mask.Test(event);
288
Andreas Gampe77708d92016-10-07 11:48:21 -0700289 if (mode == JVMTI_ENABLE) {
290 env->event_masks.EnableEvent(thread, event);
291 global_mask.Set(event);
292 } else {
293 DCHECK_EQ(mode, JVMTI_DISABLE);
294
295 env->event_masks.DisableEvent(thread, event);
296
297 // Gotta recompute the global mask.
298 bool union_value = false;
299 for (const ArtJvmTiEnv* stored_env : envs) {
300 union_value |= stored_env->event_masks.global_event_mask.Test(event);
301 union_value |= stored_env->event_masks.unioned_thread_event_mask.Test(event);
302 if (union_value) {
303 break;
304 }
305 }
306 global_mask.Set(event, union_value);
307 }
308
Andreas Gampe8b862ff2016-10-17 17:49:59 -0700309 bool new_state = global_mask.Test(event);
310
Andreas Gampe77708d92016-10-07 11:48:21 -0700311 // Handle any special work required for the event type.
Andreas Gampe8b862ff2016-10-17 17:49:59 -0700312 if (new_state != old_state) {
313 HandleEventType(event, mode == JVMTI_ENABLE);
314 }
Andreas Gampe77708d92016-10-07 11:48:21 -0700315
316 return ERR(NONE);
317}
318
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700319EventHandler::EventHandler() {
320 alloc_listener_.reset(new JvmtiAllocationListener(this));
Andreas Gampe9b8c5882016-10-21 15:27:46 -0700321 gc_pause_listener_.reset(new JvmtiGcPauseListener(this));
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700322}
323
324EventHandler::~EventHandler() {
325}
326
Andreas Gampe77708d92016-10-07 11:48:21 -0700327} // namespace openjdkjvmti