blob: 34492a91fd8c23d2b2837ed63d8b8ff114ff4329 [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
Andreas Gampe3a7eb142017-01-19 21:59:22 -0800147void EventHandler::RemoveArtJvmTiEnv(ArtJvmTiEnv* env) {
148 auto it = std::find(envs.begin(), envs.end(), env);
149 if (it != envs.end()) {
150 envs.erase(it);
151 for (size_t i = static_cast<size_t>(ArtJvmtiEvent::kMinEventTypeVal);
152 i <= static_cast<size_t>(ArtJvmtiEvent::kMaxEventTypeVal);
153 ++i) {
154 RecalculateGlobalEventMask(static_cast<ArtJvmtiEvent>(i));
155 }
156 }
157}
158
Alex Light40d87f42017-01-18 10:27:06 -0800159static bool IsThreadControllable(ArtJvmtiEvent event) {
Andreas Gampe77708d92016-10-07 11:48:21 -0700160 switch (event) {
Alex Light40d87f42017-01-18 10:27:06 -0800161 case ArtJvmtiEvent::kVmInit:
162 case ArtJvmtiEvent::kVmStart:
163 case ArtJvmtiEvent::kVmDeath:
164 case ArtJvmtiEvent::kThreadStart:
165 case ArtJvmtiEvent::kCompiledMethodLoad:
166 case ArtJvmtiEvent::kCompiledMethodUnload:
167 case ArtJvmtiEvent::kDynamicCodeGenerated:
168 case ArtJvmtiEvent::kDataDumpRequest:
Andreas Gampe77708d92016-10-07 11:48:21 -0700169 return false;
170
171 default:
172 return true;
173 }
174}
175
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700176class JvmtiAllocationListener : public art::gc::AllocationListener {
177 public:
178 explicit JvmtiAllocationListener(EventHandler* handler) : handler_(handler) {}
179
Mathieu Chartier9d156d52016-10-06 17:44:26 -0700180 void ObjectAllocated(art::Thread* self, art::ObjPtr<art::mirror::Object>* obj, size_t byte_count)
Andreas Gampe9b8c5882016-10-21 15:27:46 -0700181 OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700182 DCHECK_EQ(self, art::Thread::Current());
183
Alex Light40d87f42017-01-18 10:27:06 -0800184 if (handler_->IsEventEnabledAnywhere(ArtJvmtiEvent::kVmObjectAlloc)) {
Mathieu Chartiera7118042016-10-12 15:45:58 -0700185 art::StackHandleScope<1> hs(self);
186 auto h = hs.NewHandleWrapper(obj);
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700187 // jvmtiEventVMObjectAlloc parameters:
188 // jvmtiEnv *jvmti_env,
189 // JNIEnv* jni_env,
190 // jthread thread,
191 // jobject object,
192 // jclass object_klass,
193 // jlong size
194 art::JNIEnvExt* jni_env = self->GetJniEnv();
195
196 jthread thread_peer;
197 if (self->IsStillStarting()) {
198 thread_peer = nullptr;
199 } else {
200 thread_peer = jni_env->AddLocalReference<jthread>(self->GetPeer());
201 }
202
203 ScopedLocalRef<jthread> thread(jni_env, thread_peer);
204 ScopedLocalRef<jobject> object(
205 jni_env, jni_env->AddLocalReference<jobject>(*obj));
206 ScopedLocalRef<jclass> klass(
Mathieu Chartier9d156d52016-10-06 17:44:26 -0700207 jni_env, jni_env->AddLocalReference<jclass>(obj->Ptr()->GetClass()));
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700208
Andreas Gampe983c1752017-01-23 19:46:56 -0800209 handler_->DispatchEvent<ArtJvmtiEvent::kVmObjectAlloc>(self,
210 reinterpret_cast<JNIEnv*>(jni_env),
211 thread.get(),
212 object.get(),
213 klass.get(),
214 static_cast<jlong>(byte_count));
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700215 }
216 }
217
218 private:
219 EventHandler* handler_;
220};
221
222static void SetupObjectAllocationTracking(art::gc::AllocationListener* listener, bool enable) {
Andreas Gampec02685c2016-10-17 17:40:27 -0700223 // We must not hold the mutator lock here, but if we're in FastJNI, for example, we might. For
224 // now, do a workaround: (possibly) acquire and release.
225 art::ScopedObjectAccess soa(art::Thread::Current());
226 art::ScopedThreadSuspension sts(soa.Self(), art::ThreadState::kSuspended);
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700227 if (enable) {
228 art::Runtime::Current()->GetHeap()->SetAllocationListener(listener);
229 } else {
230 art::Runtime::Current()->GetHeap()->RemoveAllocationListener();
231 }
232}
233
Andreas Gampe9b8c5882016-10-21 15:27:46 -0700234// Report GC pauses (see spec) as GARBAGE_COLLECTION_START and GARBAGE_COLLECTION_END.
235class JvmtiGcPauseListener : public art::gc::GcPauseListener {
236 public:
237 explicit JvmtiGcPauseListener(EventHandler* handler)
238 : handler_(handler),
239 start_enabled_(false),
240 finish_enabled_(false) {}
241
242 void StartPause() OVERRIDE {
Andreas Gampe983c1752017-01-23 19:46:56 -0800243 handler_->DispatchEvent<ArtJvmtiEvent::kGarbageCollectionStart>(nullptr);
Andreas Gampe9b8c5882016-10-21 15:27:46 -0700244 }
245
246 void EndPause() OVERRIDE {
Andreas Gampe983c1752017-01-23 19:46:56 -0800247 handler_->DispatchEvent<ArtJvmtiEvent::kGarbageCollectionFinish>(nullptr);
Andreas Gampe9b8c5882016-10-21 15:27:46 -0700248 }
249
250 bool IsEnabled() {
251 return start_enabled_ || finish_enabled_;
252 }
253
254 void SetStartEnabled(bool e) {
255 start_enabled_ = e;
256 }
257
258 void SetFinishEnabled(bool e) {
259 finish_enabled_ = e;
260 }
261
262 private:
263 EventHandler* handler_;
264 bool start_enabled_;
265 bool finish_enabled_;
266};
267
Alex Light40d87f42017-01-18 10:27:06 -0800268static void SetupGcPauseTracking(JvmtiGcPauseListener* listener, ArtJvmtiEvent event, bool enable) {
Andreas Gampe9b8c5882016-10-21 15:27:46 -0700269 bool old_state = listener->IsEnabled();
270
Alex Light40d87f42017-01-18 10:27:06 -0800271 if (event == ArtJvmtiEvent::kGarbageCollectionStart) {
Andreas Gampe9b8c5882016-10-21 15:27:46 -0700272 listener->SetStartEnabled(enable);
273 } else {
274 listener->SetFinishEnabled(enable);
275 }
276
277 bool new_state = listener->IsEnabled();
278
279 if (old_state != new_state) {
280 if (new_state) {
281 art::Runtime::Current()->GetHeap()->SetGcPauseListener(listener);
282 } else {
283 art::Runtime::Current()->GetHeap()->RemoveGcPauseListener();
284 }
285 }
286}
287
Andreas Gampe77708d92016-10-07 11:48:21 -0700288// Handle special work for the given event type, if necessary.
Alex Light40d87f42017-01-18 10:27:06 -0800289void EventHandler::HandleEventType(ArtJvmtiEvent event, bool enable) {
Andreas Gampe9b8c5882016-10-21 15:27:46 -0700290 switch (event) {
Alex Light40d87f42017-01-18 10:27:06 -0800291 case ArtJvmtiEvent::kVmObjectAlloc:
Andreas Gampe9b8c5882016-10-21 15:27:46 -0700292 SetupObjectAllocationTracking(alloc_listener_.get(), enable);
293 return;
294
Alex Light40d87f42017-01-18 10:27:06 -0800295 case ArtJvmtiEvent::kGarbageCollectionStart:
296 case ArtJvmtiEvent::kGarbageCollectionFinish:
Andreas Gampe9b8c5882016-10-21 15:27:46 -0700297 SetupGcPauseTracking(gc_pause_listener_.get(), event, enable);
298 return;
299
300 default:
301 break;
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700302 }
Andreas Gampe77708d92016-10-07 11:48:21 -0700303}
304
Alex Light9db679d2017-01-25 15:28:04 -0800305// Checks to see if the env has the capabilities associated with the given event.
306static bool HasAssociatedCapability(ArtJvmTiEnv* env,
307 ArtJvmtiEvent event) {
308 jvmtiCapabilities caps = env->capabilities;
309 switch (event) {
310 case ArtJvmtiEvent::kBreakpoint:
311 return caps.can_generate_breakpoint_events == 1;
312
313 case ArtJvmtiEvent::kCompiledMethodLoad:
314 case ArtJvmtiEvent::kCompiledMethodUnload:
315 return caps.can_generate_compiled_method_load_events == 1;
316
317 case ArtJvmtiEvent::kException:
318 case ArtJvmtiEvent::kExceptionCatch:
319 return caps.can_generate_exception_events == 1;
320
321 case ArtJvmtiEvent::kFieldAccess:
322 return caps.can_generate_field_access_events == 1;
323
324 case ArtJvmtiEvent::kFieldModification:
325 return caps.can_generate_field_modification_events == 1;
326
327 case ArtJvmtiEvent::kFramePop:
328 return caps.can_generate_frame_pop_events == 1;
329
330 case ArtJvmtiEvent::kGarbageCollectionStart:
331 case ArtJvmtiEvent::kGarbageCollectionFinish:
332 return caps.can_generate_garbage_collection_events == 1;
333
334 case ArtJvmtiEvent::kMethodEntry:
335 return caps.can_generate_method_entry_events == 1;
336
337 case ArtJvmtiEvent::kMethodExit:
338 return caps.can_generate_method_exit_events == 1;
339
340 case ArtJvmtiEvent::kMonitorContendedEnter:
341 case ArtJvmtiEvent::kMonitorContendedEntered:
342 case ArtJvmtiEvent::kMonitorWait:
343 case ArtJvmtiEvent::kMonitorWaited:
344 return caps.can_generate_monitor_events == 1;
345
346 case ArtJvmtiEvent::kNativeMethodBind:
347 return caps.can_generate_native_method_bind_events == 1;
348
349 case ArtJvmtiEvent::kObjectFree:
350 return caps.can_generate_object_free_events == 1;
351
352 case ArtJvmtiEvent::kSingleStep:
353 return caps.can_generate_single_step_events == 1;
354
355 case ArtJvmtiEvent::kVmObjectAlloc:
356 return caps.can_generate_vm_object_alloc_events == 1;
357
358 default:
359 return true;
360 }
361}
362
Andreas Gampe77708d92016-10-07 11:48:21 -0700363jvmtiError EventHandler::SetEvent(ArtJvmTiEnv* env,
364 art::Thread* thread,
Alex Light40d87f42017-01-18 10:27:06 -0800365 ArtJvmtiEvent event,
Andreas Gampe77708d92016-10-07 11:48:21 -0700366 jvmtiEventMode mode) {
367 if (thread != nullptr) {
368 art::ThreadState state = thread->GetState();
369 if (state == art::ThreadState::kStarting ||
370 state == art::ThreadState::kTerminated ||
371 thread->IsStillStarting()) {
372 return ERR(THREAD_NOT_ALIVE);
373 }
374 if (!IsThreadControllable(event)) {
375 return ERR(ILLEGAL_ARGUMENT);
376 }
377 }
378
Andreas Gampe77708d92016-10-07 11:48:21 -0700379 if (mode != JVMTI_ENABLE && mode != JVMTI_DISABLE) {
380 return ERR(ILLEGAL_ARGUMENT);
381 }
382
383 if (!EventMask::EventIsInRange(event)) {
384 return ERR(INVALID_EVENT_TYPE);
385 }
386
Alex Light9db679d2017-01-25 15:28:04 -0800387 if (!HasAssociatedCapability(env, event)) {
388 return ERR(MUST_POSSESS_CAPABILITY);
389 }
390
Andreas Gampe8b862ff2016-10-17 17:49:59 -0700391 bool old_state = global_mask.Test(event);
392
Andreas Gampe77708d92016-10-07 11:48:21 -0700393 if (mode == JVMTI_ENABLE) {
394 env->event_masks.EnableEvent(thread, event);
395 global_mask.Set(event);
396 } else {
397 DCHECK_EQ(mode, JVMTI_DISABLE);
398
399 env->event_masks.DisableEvent(thread, event);
Alex Light73afd322017-01-18 11:17:47 -0800400 RecalculateGlobalEventMask(event);
Andreas Gampe77708d92016-10-07 11:48:21 -0700401 }
402
Andreas Gampe8b862ff2016-10-17 17:49:59 -0700403 bool new_state = global_mask.Test(event);
404
Andreas Gampe77708d92016-10-07 11:48:21 -0700405 // Handle any special work required for the event type.
Andreas Gampe8b862ff2016-10-17 17:49:59 -0700406 if (new_state != old_state) {
407 HandleEventType(event, mode == JVMTI_ENABLE);
408 }
Andreas Gampe77708d92016-10-07 11:48:21 -0700409
410 return ERR(NONE);
411}
412
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700413EventHandler::EventHandler() {
414 alloc_listener_.reset(new JvmtiAllocationListener(this));
Andreas Gampe9b8c5882016-10-21 15:27:46 -0700415 gc_pause_listener_.reset(new JvmtiGcPauseListener(this));
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700416}
417
418EventHandler::~EventHandler() {
419}
420
Andreas Gampe77708d92016-10-07 11:48:21 -0700421} // namespace openjdkjvmti