blob: 48f3de437cc9de7fdee42e562f422f3540bce7e6 [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
32#include "events.h"
33
34#include "art_jvmti.h"
35
36namespace openjdkjvmti {
37
38EventMask& EventMasks::GetEventMask(art::Thread* thread) {
39 if (thread == nullptr) {
40 return global_event_mask;
41 }
42
43 for (auto& pair : thread_event_masks) {
44 const UniqueThread& unique_thread = pair.first;
45 if (unique_thread.first == thread &&
46 unique_thread.second == static_cast<uint32_t>(thread->GetTid())) {
47 return pair.second;
48 }
49 }
50
51 // TODO: Remove old UniqueThread with the same pointer, if exists.
52
53 thread_event_masks.emplace_back(UniqueThread(thread, thread->GetTid()), EventMask());
54 return thread_event_masks.back().second;
55}
56
57EventMask* EventMasks::GetEventMaskOrNull(art::Thread* thread) {
58 if (thread == nullptr) {
59 return &global_event_mask;
60 }
61
62 for (auto& pair : thread_event_masks) {
63 const UniqueThread& unique_thread = pair.first;
64 if (unique_thread.first == thread &&
65 unique_thread.second == static_cast<uint32_t>(thread->GetTid())) {
66 return &pair.second;
67 }
68 }
69
70 return nullptr;
71}
72
73
74void EventMasks::EnableEvent(art::Thread* thread, jvmtiEvent event) {
75 DCHECK(EventMask::EventIsInRange(event));
76 GetEventMask(thread).Set(event);
77 if (thread != nullptr) {
78 unioned_thread_event_mask.Set(event, true);
79 }
80}
81
82void EventMasks::DisableEvent(art::Thread* thread, jvmtiEvent event) {
83 DCHECK(EventMask::EventIsInRange(event));
84 GetEventMask(thread).Set(event, false);
85 if (thread != nullptr) {
86 // Regenerate union for the event.
87 bool union_value = false;
88 for (auto& pair : thread_event_masks) {
89 union_value |= pair.second.Test(event);
90 if (union_value) {
91 break;
92 }
93 }
94 unioned_thread_event_mask.Set(event, union_value);
95 }
96}
97
98void EventHandler::RegisterArtJvmTiEnv(ArtJvmTiEnv* env) {
99 envs.push_back(env);
100}
101
102static bool IsThreadControllable(jvmtiEvent event) {
103 switch (event) {
104 case JVMTI_EVENT_VM_INIT:
105 case JVMTI_EVENT_VM_START:
106 case JVMTI_EVENT_VM_DEATH:
107 case JVMTI_EVENT_THREAD_START:
108 case JVMTI_EVENT_COMPILED_METHOD_LOAD:
109 case JVMTI_EVENT_COMPILED_METHOD_UNLOAD:
110 case JVMTI_EVENT_DYNAMIC_CODE_GENERATED:
111 case JVMTI_EVENT_DATA_DUMP_REQUEST:
112 return false;
113
114 default:
115 return true;
116 }
117}
118
119// Handle special work for the given event type, if necessary.
120static void HandleEventType(jvmtiEvent event ATTRIBUTE_UNUSED, bool enable ATTRIBUTE_UNUSED) {
121}
122
123jvmtiError EventHandler::SetEvent(ArtJvmTiEnv* env,
124 art::Thread* thread,
125 jvmtiEvent event,
126 jvmtiEventMode mode) {
127 if (thread != nullptr) {
128 art::ThreadState state = thread->GetState();
129 if (state == art::ThreadState::kStarting ||
130 state == art::ThreadState::kTerminated ||
131 thread->IsStillStarting()) {
132 return ERR(THREAD_NOT_ALIVE);
133 }
134 if (!IsThreadControllable(event)) {
135 return ERR(ILLEGAL_ARGUMENT);
136 }
137 }
138
139 // TODO: Capability check.
140
141 if (mode != JVMTI_ENABLE && mode != JVMTI_DISABLE) {
142 return ERR(ILLEGAL_ARGUMENT);
143 }
144
145 if (!EventMask::EventIsInRange(event)) {
146 return ERR(INVALID_EVENT_TYPE);
147 }
148
149 if (mode == JVMTI_ENABLE) {
150 env->event_masks.EnableEvent(thread, event);
151 global_mask.Set(event);
152 } else {
153 DCHECK_EQ(mode, JVMTI_DISABLE);
154
155 env->event_masks.DisableEvent(thread, event);
156
157 // Gotta recompute the global mask.
158 bool union_value = false;
159 for (const ArtJvmTiEnv* stored_env : envs) {
160 union_value |= stored_env->event_masks.global_event_mask.Test(event);
161 union_value |= stored_env->event_masks.unioned_thread_event_mask.Test(event);
162 if (union_value) {
163 break;
164 }
165 }
166 global_mask.Set(event, union_value);
167 }
168
169 // Handle any special work required for the event type.
170 HandleEventType(event, mode == JVMTI_ENABLE);
171
172 return ERR(NONE);
173}
174
175} // namespace openjdkjvmti