blob: 7e4ee8491dee790f19a74ff60560305846ec5610 [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)) {
136 // jvmtiEventVMObjectAlloc parameters:
137 // jvmtiEnv *jvmti_env,
138 // JNIEnv* jni_env,
139 // jthread thread,
140 // jobject object,
141 // jclass object_klass,
142 // jlong size
143 art::JNIEnvExt* jni_env = self->GetJniEnv();
144
145 jthread thread_peer;
146 if (self->IsStillStarting()) {
147 thread_peer = nullptr;
148 } else {
149 thread_peer = jni_env->AddLocalReference<jthread>(self->GetPeer());
150 }
151
152 ScopedLocalRef<jthread> thread(jni_env, thread_peer);
153 ScopedLocalRef<jobject> object(
154 jni_env, jni_env->AddLocalReference<jobject>(*obj));
155 ScopedLocalRef<jclass> klass(
Mathieu Chartier9d156d52016-10-06 17:44:26 -0700156 jni_env, jni_env->AddLocalReference<jclass>(obj->Ptr()->GetClass()));
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700157
158 handler_->DispatchEvent(self,
159 JVMTI_EVENT_VM_OBJECT_ALLOC,
160 jni_env,
161 thread.get(),
162 object.get(),
163 klass.get(),
164 byte_count);
165 }
166 }
167
168 private:
169 EventHandler* handler_;
170};
171
172static void SetupObjectAllocationTracking(art::gc::AllocationListener* listener, bool enable) {
173 if (enable) {
174 art::Runtime::Current()->GetHeap()->SetAllocationListener(listener);
175 } else {
176 art::Runtime::Current()->GetHeap()->RemoveAllocationListener();
177 }
178}
179
Andreas Gampe77708d92016-10-07 11:48:21 -0700180// Handle special work for the given event type, if necessary.
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700181void EventHandler::HandleEventType(jvmtiEvent event, bool enable) {
182 if (event == JVMTI_EVENT_VM_OBJECT_ALLOC) {
183 SetupObjectAllocationTracking(alloc_listener_.get(), enable);
184 return;
185 }
Andreas Gampe77708d92016-10-07 11:48:21 -0700186}
187
188jvmtiError EventHandler::SetEvent(ArtJvmTiEnv* env,
189 art::Thread* thread,
190 jvmtiEvent event,
191 jvmtiEventMode mode) {
192 if (thread != nullptr) {
193 art::ThreadState state = thread->GetState();
194 if (state == art::ThreadState::kStarting ||
195 state == art::ThreadState::kTerminated ||
196 thread->IsStillStarting()) {
197 return ERR(THREAD_NOT_ALIVE);
198 }
199 if (!IsThreadControllable(event)) {
200 return ERR(ILLEGAL_ARGUMENT);
201 }
202 }
203
204 // TODO: Capability check.
205
206 if (mode != JVMTI_ENABLE && mode != JVMTI_DISABLE) {
207 return ERR(ILLEGAL_ARGUMENT);
208 }
209
210 if (!EventMask::EventIsInRange(event)) {
211 return ERR(INVALID_EVENT_TYPE);
212 }
213
214 if (mode == JVMTI_ENABLE) {
215 env->event_masks.EnableEvent(thread, event);
216 global_mask.Set(event);
217 } else {
218 DCHECK_EQ(mode, JVMTI_DISABLE);
219
220 env->event_masks.DisableEvent(thread, event);
221
222 // Gotta recompute the global mask.
223 bool union_value = false;
224 for (const ArtJvmTiEnv* stored_env : envs) {
225 union_value |= stored_env->event_masks.global_event_mask.Test(event);
226 union_value |= stored_env->event_masks.unioned_thread_event_mask.Test(event);
227 if (union_value) {
228 break;
229 }
230 }
231 global_mask.Set(event, union_value);
232 }
233
234 // Handle any special work required for the event type.
235 HandleEventType(event, mode == JVMTI_ENABLE);
236
237 return ERR(NONE);
238}
239
Andreas Gampe27fa96c2016-10-07 15:05:24 -0700240EventHandler::EventHandler() {
241 alloc_listener_.reset(new JvmtiAllocationListener(this));
242}
243
244EventHandler::~EventHandler() {
245}
246
Andreas Gampe77708d92016-10-07 11:48:21 -0700247} // namespace openjdkjvmti