blob: f38aa869d9b826d6e507d41ba60c50cc45f36c27 [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
Alex Light73afd322017-01-18 11:17:47 -080050bool EventMasks::IsEnabledAnywhere(ArtJvmtiEvent event) {
51 return global_event_mask.Test(event) || unioned_thread_event_mask.Test(event);
52}
53
Andreas Gampe77708d92016-10-07 11:48:21 -070054EventMask& EventMasks::GetEventMask(art::Thread* thread) {
55 if (thread == nullptr) {
56 return global_event_mask;
57 }
58
59 for (auto& pair : thread_event_masks) {
60 const UniqueThread& unique_thread = pair.first;
61 if (unique_thread.first == thread &&
62 unique_thread.second == static_cast<uint32_t>(thread->GetTid())) {
63 return pair.second;
64 }
65 }
66
67 // TODO: Remove old UniqueThread with the same pointer, if exists.
68
69 thread_event_masks.emplace_back(UniqueThread(thread, thread->GetTid()), EventMask());
70 return thread_event_masks.back().second;
71}
72
73EventMask* EventMasks::GetEventMaskOrNull(art::Thread* thread) {
74 if (thread == nullptr) {
75 return &global_event_mask;
76 }
77
78 for (auto& pair : thread_event_masks) {
79 const UniqueThread& unique_thread = pair.first;
80 if (unique_thread.first == thread &&
81 unique_thread.second == static_cast<uint32_t>(thread->GetTid())) {
82 return &pair.second;
83 }
84 }
85
86 return nullptr;
87}
88
89
Alex Light40d87f42017-01-18 10:27:06 -080090void EventMasks::EnableEvent(art::Thread* thread, ArtJvmtiEvent event) {
Andreas Gampe77708d92016-10-07 11:48:21 -070091 DCHECK(EventMask::EventIsInRange(event));
92 GetEventMask(thread).Set(event);
93 if (thread != nullptr) {
94 unioned_thread_event_mask.Set(event, true);
95 }
96}
97
Alex Light40d87f42017-01-18 10:27:06 -080098void EventMasks::DisableEvent(art::Thread* thread, ArtJvmtiEvent event) {
Andreas Gampe77708d92016-10-07 11:48:21 -070099 DCHECK(EventMask::EventIsInRange(event));
100 GetEventMask(thread).Set(event, false);
101 if (thread != nullptr) {
102 // Regenerate union for the event.
103 bool union_value = false;
104 for (auto& pair : thread_event_masks) {
105 union_value |= pair.second.Test(event);
106 if (union_value) {
107 break;
108 }
109 }
110 unioned_thread_event_mask.Set(event, union_value);
111 }
112}
113
Alex Light73afd322017-01-18 11:17:47 -0800114void EventMasks::HandleChangedCapabilities(const jvmtiCapabilities& caps, bool caps_added) {
115 if (UNLIKELY(caps.can_retransform_classes == 1)) {
116 // If we are giving this env the retransform classes cap we need to switch all events of
117 // NonTransformable to Transformable and vice versa.
118 ArtJvmtiEvent to_remove = caps_added ? ArtJvmtiEvent::kClassFileLoadHookNonRetransformable
119 : ArtJvmtiEvent::kClassFileLoadHookRetransformable;
120 ArtJvmtiEvent to_add = caps_added ? ArtJvmtiEvent::kClassFileLoadHookRetransformable
121 : ArtJvmtiEvent::kClassFileLoadHookNonRetransformable;
122 if (global_event_mask.Test(to_remove)) {
123 CHECK(!global_event_mask.Test(to_add));
124 global_event_mask.Set(to_remove, false);
125 global_event_mask.Set(to_add, true);
126 }
127
128 if (unioned_thread_event_mask.Test(to_remove)) {
129 CHECK(!unioned_thread_event_mask.Test(to_add));
130 unioned_thread_event_mask.Set(to_remove, false);
131 unioned_thread_event_mask.Set(to_add, true);
132 }
133 for (auto thread_mask : thread_event_masks) {
134 if (thread_mask.second.Test(to_remove)) {
135 CHECK(!thread_mask.second.Test(to_add));
136 thread_mask.second.Set(to_remove, false);
137 thread_mask.second.Set(to_add, true);
138 }
139 }
140 }
141}
142
Andreas Gampe77708d92016-10-07 11:48:21 -0700143void EventHandler::RegisterArtJvmTiEnv(ArtJvmTiEnv* env) {
144 envs.push_back(env);
145}
146
Alex Light40d87f42017-01-18 10:27:06 -0800147static bool IsThreadControllable(ArtJvmtiEvent event) {
Andreas Gampe77708d92016-10-07 11:48:21 -0700148 switch (event) {
Alex Light40d87f42017-01-18 10:27:06 -0800149 case ArtJvmtiEvent::kVmInit:
150 case ArtJvmtiEvent::kVmStart:
151 case ArtJvmtiEvent::kVmDeath:
152 case ArtJvmtiEvent::kThreadStart:
153 case ArtJvmtiEvent::kCompiledMethodLoad:
154 case ArtJvmtiEvent::kCompiledMethodUnload:
155 case ArtJvmtiEvent::kDynamicCodeGenerated:
156 case ArtJvmtiEvent::kDataDumpRequest:
Andreas Gampe77708d92016-10-07 11:48:21 -0700157 return false;
158
159 default:
160 return true;
161 }
162}
163
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700164class JvmtiAllocationListener : public art::gc::AllocationListener {
165 public:
166 explicit JvmtiAllocationListener(EventHandler* handler) : handler_(handler) {}
167
Mathieu Chartier9d156d52016-10-06 17:44:26 -0700168 void ObjectAllocated(art::Thread* self, art::ObjPtr<art::mirror::Object>* obj, size_t byte_count)
Andreas Gampe9b8c5882016-10-21 15:27:46 -0700169 OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700170 DCHECK_EQ(self, art::Thread::Current());
171
Alex Light40d87f42017-01-18 10:27:06 -0800172 if (handler_->IsEventEnabledAnywhere(ArtJvmtiEvent::kVmObjectAlloc)) {
Mathieu Chartiera7118042016-10-12 15:45:58 -0700173 art::StackHandleScope<1> hs(self);
174 auto h = hs.NewHandleWrapper(obj);
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700175 // jvmtiEventVMObjectAlloc parameters:
176 // jvmtiEnv *jvmti_env,
177 // JNIEnv* jni_env,
178 // jthread thread,
179 // jobject object,
180 // jclass object_klass,
181 // jlong size
182 art::JNIEnvExt* jni_env = self->GetJniEnv();
183
184 jthread thread_peer;
185 if (self->IsStillStarting()) {
186 thread_peer = nullptr;
187 } else {
188 thread_peer = jni_env->AddLocalReference<jthread>(self->GetPeer());
189 }
190
191 ScopedLocalRef<jthread> thread(jni_env, thread_peer);
192 ScopedLocalRef<jobject> object(
193 jni_env, jni_env->AddLocalReference<jobject>(*obj));
194 ScopedLocalRef<jclass> klass(
Mathieu Chartier9d156d52016-10-06 17:44:26 -0700195 jni_env, jni_env->AddLocalReference<jclass>(obj->Ptr()->GetClass()));
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700196
197 handler_->DispatchEvent(self,
Alex Light40d87f42017-01-18 10:27:06 -0800198 ArtJvmtiEvent::kVmObjectAlloc,
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700199 jni_env,
200 thread.get(),
201 object.get(),
202 klass.get(),
203 byte_count);
204 }
205 }
206
207 private:
208 EventHandler* handler_;
209};
210
211static void SetupObjectAllocationTracking(art::gc::AllocationListener* listener, bool enable) {
Andreas Gampec02685c2016-10-17 17:40:27 -0700212 // We must not hold the mutator lock here, but if we're in FastJNI, for example, we might. For
213 // now, do a workaround: (possibly) acquire and release.
214 art::ScopedObjectAccess soa(art::Thread::Current());
215 art::ScopedThreadSuspension sts(soa.Self(), art::ThreadState::kSuspended);
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700216 if (enable) {
217 art::Runtime::Current()->GetHeap()->SetAllocationListener(listener);
218 } else {
219 art::Runtime::Current()->GetHeap()->RemoveAllocationListener();
220 }
221}
222
Andreas Gampe9b8c5882016-10-21 15:27:46 -0700223// Report GC pauses (see spec) as GARBAGE_COLLECTION_START and GARBAGE_COLLECTION_END.
224class JvmtiGcPauseListener : public art::gc::GcPauseListener {
225 public:
226 explicit JvmtiGcPauseListener(EventHandler* handler)
227 : handler_(handler),
228 start_enabled_(false),
229 finish_enabled_(false) {}
230
231 void StartPause() OVERRIDE {
Alex Light40d87f42017-01-18 10:27:06 -0800232 handler_->DispatchEvent(nullptr, ArtJvmtiEvent::kGarbageCollectionStart);
Andreas Gampe9b8c5882016-10-21 15:27:46 -0700233 }
234
235 void EndPause() OVERRIDE {
Alex Light40d87f42017-01-18 10:27:06 -0800236 handler_->DispatchEvent(nullptr, ArtJvmtiEvent::kGarbageCollectionFinish);
Andreas Gampe9b8c5882016-10-21 15:27:46 -0700237 }
238
239 bool IsEnabled() {
240 return start_enabled_ || finish_enabled_;
241 }
242
243 void SetStartEnabled(bool e) {
244 start_enabled_ = e;
245 }
246
247 void SetFinishEnabled(bool e) {
248 finish_enabled_ = e;
249 }
250
251 private:
252 EventHandler* handler_;
253 bool start_enabled_;
254 bool finish_enabled_;
255};
256
Alex Light40d87f42017-01-18 10:27:06 -0800257static void SetupGcPauseTracking(JvmtiGcPauseListener* listener, ArtJvmtiEvent event, bool enable) {
Andreas Gampe9b8c5882016-10-21 15:27:46 -0700258 bool old_state = listener->IsEnabled();
259
Alex Light40d87f42017-01-18 10:27:06 -0800260 if (event == ArtJvmtiEvent::kGarbageCollectionStart) {
Andreas Gampe9b8c5882016-10-21 15:27:46 -0700261 listener->SetStartEnabled(enable);
262 } else {
263 listener->SetFinishEnabled(enable);
264 }
265
266 bool new_state = listener->IsEnabled();
267
268 if (old_state != new_state) {
269 if (new_state) {
270 art::Runtime::Current()->GetHeap()->SetGcPauseListener(listener);
271 } else {
272 art::Runtime::Current()->GetHeap()->RemoveGcPauseListener();
273 }
274 }
275}
276
Andreas Gampe77708d92016-10-07 11:48:21 -0700277// Handle special work for the given event type, if necessary.
Alex Light40d87f42017-01-18 10:27:06 -0800278void EventHandler::HandleEventType(ArtJvmtiEvent event, bool enable) {
Andreas Gampe9b8c5882016-10-21 15:27:46 -0700279 switch (event) {
Alex Light40d87f42017-01-18 10:27:06 -0800280 case ArtJvmtiEvent::kVmObjectAlloc:
Andreas Gampe9b8c5882016-10-21 15:27:46 -0700281 SetupObjectAllocationTracking(alloc_listener_.get(), enable);
282 return;
283
Alex Light40d87f42017-01-18 10:27:06 -0800284 case ArtJvmtiEvent::kGarbageCollectionStart:
285 case ArtJvmtiEvent::kGarbageCollectionFinish:
Andreas Gampe9b8c5882016-10-21 15:27:46 -0700286 SetupGcPauseTracking(gc_pause_listener_.get(), event, enable);
287 return;
288
289 default:
290 break;
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700291 }
Andreas Gampe77708d92016-10-07 11:48:21 -0700292}
293
294jvmtiError EventHandler::SetEvent(ArtJvmTiEnv* env,
295 art::Thread* thread,
Alex Light40d87f42017-01-18 10:27:06 -0800296 ArtJvmtiEvent event,
Andreas Gampe77708d92016-10-07 11:48:21 -0700297 jvmtiEventMode mode) {
298 if (thread != nullptr) {
299 art::ThreadState state = thread->GetState();
300 if (state == art::ThreadState::kStarting ||
301 state == art::ThreadState::kTerminated ||
302 thread->IsStillStarting()) {
303 return ERR(THREAD_NOT_ALIVE);
304 }
305 if (!IsThreadControllable(event)) {
306 return ERR(ILLEGAL_ARGUMENT);
307 }
308 }
309
310 // TODO: Capability check.
311
312 if (mode != JVMTI_ENABLE && mode != JVMTI_DISABLE) {
313 return ERR(ILLEGAL_ARGUMENT);
314 }
315
316 if (!EventMask::EventIsInRange(event)) {
317 return ERR(INVALID_EVENT_TYPE);
318 }
319
Andreas Gampe8b862ff2016-10-17 17:49:59 -0700320 bool old_state = global_mask.Test(event);
321
Andreas Gampe77708d92016-10-07 11:48:21 -0700322 if (mode == JVMTI_ENABLE) {
323 env->event_masks.EnableEvent(thread, event);
324 global_mask.Set(event);
325 } else {
326 DCHECK_EQ(mode, JVMTI_DISABLE);
327
328 env->event_masks.DisableEvent(thread, event);
Alex Light73afd322017-01-18 11:17:47 -0800329 RecalculateGlobalEventMask(event);
Andreas Gampe77708d92016-10-07 11:48:21 -0700330 }
331
Andreas Gampe8b862ff2016-10-17 17:49:59 -0700332 bool new_state = global_mask.Test(event);
333
Andreas Gampe77708d92016-10-07 11:48:21 -0700334 // Handle any special work required for the event type.
Andreas Gampe8b862ff2016-10-17 17:49:59 -0700335 if (new_state != old_state) {
336 HandleEventType(event, mode == JVMTI_ENABLE);
337 }
Andreas Gampe77708d92016-10-07 11:48:21 -0700338
339 return ERR(NONE);
340}
341
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700342EventHandler::EventHandler() {
343 alloc_listener_.reset(new JvmtiAllocationListener(this));
Andreas Gampe9b8c5882016-10-21 15:27:46 -0700344 gc_pause_listener_.reset(new JvmtiGcPauseListener(this));
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700345}
346
347EventHandler::~EventHandler() {
348}
349
Andreas Gampe77708d92016-10-07 11:48:21 -0700350} // namespace openjdkjvmti