blob: a6f1207f34fd5d628e96c82828e5e2b64c53530f [file] [log] [blame]
Alex Light0fa17862017-10-24 13:43:05 -07001/* Copyright (C) 2017 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 <functional>
33
34#include "deopt_manager.h"
35
36#include "art_jvmti.h"
37#include "art_method-inl.h"
38#include "base/enums.h"
39#include "base/mutex-inl.h"
David Sehr9e734c72018-01-04 17:56:19 -080040#include "dex/dex_file_annotations.h"
David Sehr8c0961f2018-01-23 16:11:38 -080041#include "dex/modifiers.h"
Alex Light0fa17862017-10-24 13:43:05 -070042#include "events-inl.h"
43#include "jni_internal.h"
44#include "mirror/class-inl.h"
45#include "mirror/object_array-inl.h"
Alex Light0fa17862017-10-24 13:43:05 -070046#include "nativehelper/scoped_local_ref.h"
47#include "runtime_callbacks.h"
48#include "scoped_thread_state_change-inl.h"
49#include "thread-current-inl.h"
50#include "thread_list.h"
51#include "ti_phase.h"
52
53namespace openjdkjvmti {
54
55// TODO We should make this much more selective in the future so we only return true when we
Alex Lightf2858632018-04-02 11:28:50 -070056// actually care about the method at this time (ie active frames had locals changed). For now we
57// just assume that if anything has changed any frame's locals we care about all methods. If nothing
58// has we only care about methods with active breakpoints on them. In the future we should probably
59// rewrite all of this to instead do this at the ShadowFrame or thread granularity.
60bool JvmtiMethodInspectionCallback::IsMethodBeingInspected(art::ArtMethod* method) {
61 // Non-java-debuggable runtimes we need to assume that any method might not be debuggable and
62 // therefore potentially being inspected (due to inlines). If we are debuggable we rely hard on
63 // inlining not being done since we don't keep track of which methods get inlined where and simply
64 // look to see if the method is breakpointed.
65 return !art::Runtime::Current()->IsJavaDebuggable() ||
66 manager_->HaveLocalsChanged() ||
67 manager_->MethodHasBreakpoints(method);
Alex Light0fa17862017-10-24 13:43:05 -070068}
69
70bool JvmtiMethodInspectionCallback::IsMethodSafeToJit(art::ArtMethod* method) {
71 return !manager_->MethodHasBreakpoints(method);
72}
73
Alex Lightf2858632018-04-02 11:28:50 -070074bool JvmtiMethodInspectionCallback::MethodNeedsDebugVersion(
75 art::ArtMethod* method ATTRIBUTE_UNUSED) {
76 return true;
77}
78
Alex Light0fa17862017-10-24 13:43:05 -070079DeoptManager::DeoptManager()
Alex Light2ce6fc82017-12-18 16:42:36 -080080 : deoptimization_status_lock_("JVMTI_DeoptimizationStatusLock",
81 static_cast<art::LockLevel>(
82 art::LockLevel::kClassLinkerClassesLock + 1)),
Alex Light0fa17862017-10-24 13:43:05 -070083 deoptimization_condition_("JVMTI_DeoptimizationCondition", deoptimization_status_lock_),
84 performing_deoptimization_(false),
85 global_deopt_count_(0),
86 deopter_count_(0),
Alex Lightf2858632018-04-02 11:28:50 -070087 breakpoint_status_lock_("JVMTI_BreakpointStatusLock",
88 static_cast<art::LockLevel>(art::LockLevel::kAbortLock + 1)),
89 inspection_callback_(this),
90 set_local_variable_called_(false) { }
Alex Light0fa17862017-10-24 13:43:05 -070091
92void DeoptManager::Setup() {
93 art::ScopedThreadStateChange stsc(art::Thread::Current(),
94 art::ThreadState::kWaitingForDebuggerToAttach);
95 art::ScopedSuspendAll ssa("Add method Inspection Callback");
96 art::RuntimeCallbacks* callbacks = art::Runtime::Current()->GetRuntimeCallbacks();
97 callbacks->AddMethodInspectionCallback(&inspection_callback_);
98}
99
100void DeoptManager::Shutdown() {
101 art::ScopedThreadStateChange stsc(art::Thread::Current(),
102 art::ThreadState::kWaitingForDebuggerToAttach);
103 art::ScopedSuspendAll ssa("remove method Inspection Callback");
104 art::RuntimeCallbacks* callbacks = art::Runtime::Current()->GetRuntimeCallbacks();
105 callbacks->RemoveMethodInspectionCallback(&inspection_callback_);
106}
107
Alex Light2ce6fc82017-12-18 16:42:36 -0800108void DeoptManager::FinishSetup() {
109 art::Thread* self = art::Thread::Current();
110 art::MutexLock mu(self, deoptimization_status_lock_);
111
112 art::Runtime* runtime = art::Runtime::Current();
113 // See if we need to do anything.
114 if (!runtime->IsJavaDebuggable()) {
115 // See if we can enable all JVMTI functions. If this is false, only kArtTiVersion agents can be
116 // retrieved and they will all be best-effort.
117 if (PhaseUtil::GetPhaseUnchecked() == JVMTI_PHASE_ONLOAD) {
118 // We are still early enough to change the compiler options and get full JVMTI support.
119 LOG(INFO) << "Openjdkjvmti plugin loaded on a non-debuggable runtime. Changing runtime to "
120 << "debuggable state. Please pass '--debuggable' to dex2oat and "
121 << "'-Xcompiler-option --debuggable' to dalvikvm in the future.";
122 DCHECK(runtime->GetJit() == nullptr) << "Jit should not be running yet!";
123 runtime->AddCompilerOption("--debuggable");
124 runtime->SetJavaDebuggable(true);
125 } else {
126 LOG(WARNING) << "Openjdkjvmti plugin was loaded on a non-debuggable Runtime. Plugin was "
127 << "loaded too late to change runtime state to DEBUGGABLE. Only kArtTiVersion "
128 << "(0x" << std::hex << kArtTiVersion << ") environments are available. Some "
129 << "functionality might not work properly.";
130 }
131 runtime->DeoptimizeBootImage();
132 }
133}
134
Alex Light0fa17862017-10-24 13:43:05 -0700135bool DeoptManager::MethodHasBreakpoints(art::ArtMethod* method) {
Alex Lightf2858632018-04-02 11:28:50 -0700136 art::MutexLock lk(art::Thread::Current(), breakpoint_status_lock_);
Alex Light0fa17862017-10-24 13:43:05 -0700137 return MethodHasBreakpointsLocked(method);
138}
139
140bool DeoptManager::MethodHasBreakpointsLocked(art::ArtMethod* method) {
Alex Light0fa17862017-10-24 13:43:05 -0700141 auto elem = breakpoint_status_.find(method);
142 return elem != breakpoint_status_.end() && elem->second != 0;
143}
144
145void DeoptManager::RemoveDeoptimizeAllMethods() {
146 art::Thread* self = art::Thread::Current();
147 art::ScopedThreadSuspension sts(self, art::kSuspended);
148 deoptimization_status_lock_.ExclusiveLock(self);
149 RemoveDeoptimizeAllMethodsLocked(self);
150}
151
152void DeoptManager::AddDeoptimizeAllMethods() {
153 art::Thread* self = art::Thread::Current();
154 art::ScopedThreadSuspension sts(self, art::kSuspended);
155 deoptimization_status_lock_.ExclusiveLock(self);
156 AddDeoptimizeAllMethodsLocked(self);
157}
158
159void DeoptManager::AddMethodBreakpoint(art::ArtMethod* method) {
160 DCHECK(method->IsInvokable());
161 DCHECK(!method->IsProxyMethod()) << method->PrettyMethod();
162 DCHECK(!method->IsNative()) << method->PrettyMethod();
163
164 art::Thread* self = art::Thread::Current();
165 method = method->GetCanonicalMethod();
166 bool is_default = method->IsDefault();
167
168 art::ScopedThreadSuspension sts(self, art::kSuspended);
169 deoptimization_status_lock_.ExclusiveLock(self);
Alex Lightf2858632018-04-02 11:28:50 -0700170 {
171 breakpoint_status_lock_.ExclusiveLock(self);
Alex Light0fa17862017-10-24 13:43:05 -0700172
Alex Lightf2858632018-04-02 11:28:50 -0700173 DCHECK_GT(deopter_count_, 0u) << "unexpected deotpimization request";
Alex Light0fa17862017-10-24 13:43:05 -0700174
Alex Lightf2858632018-04-02 11:28:50 -0700175 if (MethodHasBreakpointsLocked(method)) {
176 // Don't need to do anything extra.
177 breakpoint_status_[method]++;
178 // Another thread might be deoptimizing the very method we just added new breakpoints for.
179 // Wait for any deopts to finish before moving on.
180 breakpoint_status_lock_.ExclusiveUnlock(self);
181 WaitForDeoptimizationToFinish(self);
182 return;
183 }
184 breakpoint_status_[method] = 1;
185 breakpoint_status_lock_.ExclusiveUnlock(self);
Alex Light0fa17862017-10-24 13:43:05 -0700186 }
Alex Light0fa17862017-10-24 13:43:05 -0700187 auto instrumentation = art::Runtime::Current()->GetInstrumentation();
188 if (instrumentation->IsForcedInterpretOnly()) {
189 // We are already interpreting everything so no need to do anything.
190 deoptimization_status_lock_.ExclusiveUnlock(self);
191 return;
192 } else if (is_default) {
193 AddDeoptimizeAllMethodsLocked(self);
194 } else {
195 PerformLimitedDeoptimization(self, method);
196 }
197}
198
199void DeoptManager::RemoveMethodBreakpoint(art::ArtMethod* method) {
200 DCHECK(method->IsInvokable()) << method->PrettyMethod();
201 DCHECK(!method->IsProxyMethod()) << method->PrettyMethod();
202 DCHECK(!method->IsNative()) << method->PrettyMethod();
203
204 art::Thread* self = art::Thread::Current();
205 method = method->GetCanonicalMethod();
206 bool is_default = method->IsDefault();
207
208 art::ScopedThreadSuspension sts(self, art::kSuspended);
209 // Ideally we should do a ScopedSuspendAll right here to get the full mutator_lock_ that we might
210 // need but since that is very heavy we will instead just use a condition variable to make sure we
211 // don't race with ourselves.
212 deoptimization_status_lock_.ExclusiveLock(self);
Alex Lightf2858632018-04-02 11:28:50 -0700213 bool is_last_breakpoint;
214 {
215 art::MutexLock mu(self, breakpoint_status_lock_);
Alex Light0fa17862017-10-24 13:43:05 -0700216
Alex Lightf2858632018-04-02 11:28:50 -0700217 DCHECK_GT(deopter_count_, 0u) << "unexpected deotpimization request";
218 DCHECK(MethodHasBreakpointsLocked(method)) << "Breakpoint on a method was removed without "
219 << "breakpoints present!";
220 breakpoint_status_[method] -= 1;
221 is_last_breakpoint = (breakpoint_status_[method] == 0);
222 }
Alex Light0fa17862017-10-24 13:43:05 -0700223 auto instrumentation = art::Runtime::Current()->GetInstrumentation();
Alex Light0fa17862017-10-24 13:43:05 -0700224 if (UNLIKELY(instrumentation->IsForcedInterpretOnly())) {
225 // We don't need to do anything since we are interpreting everything anyway.
226 deoptimization_status_lock_.ExclusiveUnlock(self);
227 return;
Alex Lightf2858632018-04-02 11:28:50 -0700228 } else if (is_last_breakpoint) {
Alex Light0fa17862017-10-24 13:43:05 -0700229 if (UNLIKELY(is_default)) {
230 RemoveDeoptimizeAllMethodsLocked(self);
231 } else {
232 PerformLimitedUndeoptimization(self, method);
233 }
234 } else {
235 // Another thread might be deoptimizing the very methods we just removed breakpoints from. Wait
236 // for any deopts to finish before moving on.
237 WaitForDeoptimizationToFinish(self);
238 }
239}
240
241void DeoptManager::WaitForDeoptimizationToFinishLocked(art::Thread* self) {
242 while (performing_deoptimization_) {
243 deoptimization_condition_.Wait(self);
244 }
245}
246
247void DeoptManager::WaitForDeoptimizationToFinish(art::Thread* self) {
248 WaitForDeoptimizationToFinishLocked(self);
249 deoptimization_status_lock_.ExclusiveUnlock(self);
250}
251
252class ScopedDeoptimizationContext : public art::ValueObject {
253 public:
254 ScopedDeoptimizationContext(art::Thread* self, DeoptManager* deopt)
255 RELEASE(deopt->deoptimization_status_lock_)
256 ACQUIRE(art::Locks::mutator_lock_)
257 ACQUIRE(art::Roles::uninterruptible_)
258 : self_(self), deopt_(deopt), uninterruptible_cause_(nullptr) {
259 deopt_->WaitForDeoptimizationToFinishLocked(self_);
260 DCHECK(!deopt->performing_deoptimization_)
261 << "Already performing deoptimization on another thread!";
262 // Use performing_deoptimization_ to keep track of the lock.
263 deopt_->performing_deoptimization_ = true;
264 deopt_->deoptimization_status_lock_.Unlock(self_);
265 art::Runtime::Current()->GetThreadList()->SuspendAll("JMVTI Deoptimizing methods",
266 /*long_suspend*/ false);
267 uninterruptible_cause_ = self_->StartAssertNoThreadSuspension("JVMTI deoptimizing methods");
268 }
269
270 ~ScopedDeoptimizationContext()
271 RELEASE(art::Locks::mutator_lock_)
272 RELEASE(art::Roles::uninterruptible_) {
273 // Can be suspended again.
274 self_->EndAssertNoThreadSuspension(uninterruptible_cause_);
275 // Release the mutator lock.
276 art::Runtime::Current()->GetThreadList()->ResumeAll();
277 // Let other threads know it's fine to proceed.
278 art::MutexLock lk(self_, deopt_->deoptimization_status_lock_);
279 deopt_->performing_deoptimization_ = false;
280 deopt_->deoptimization_condition_.Broadcast(self_);
281 }
282
283 private:
284 art::Thread* self_;
285 DeoptManager* deopt_;
286 const char* uninterruptible_cause_;
287};
288
289void DeoptManager::AddDeoptimizeAllMethodsLocked(art::Thread* self) {
290 global_deopt_count_++;
291 if (global_deopt_count_ == 1) {
292 PerformGlobalDeoptimization(self);
293 } else {
294 WaitForDeoptimizationToFinish(self);
295 }
296}
297
298void DeoptManager::RemoveDeoptimizeAllMethodsLocked(art::Thread* self) {
Roland Levillainef012222017-06-21 16:28:06 +0100299 DCHECK_GT(global_deopt_count_, 0u) << "Request to remove non-existent global deoptimization!";
Alex Light0fa17862017-10-24 13:43:05 -0700300 global_deopt_count_--;
301 if (global_deopt_count_ == 0) {
302 PerformGlobalUndeoptimization(self);
303 } else {
304 WaitForDeoptimizationToFinish(self);
305 }
306}
307
308void DeoptManager::PerformLimitedDeoptimization(art::Thread* self, art::ArtMethod* method) {
309 ScopedDeoptimizationContext sdc(self, this);
310 art::Runtime::Current()->GetInstrumentation()->Deoptimize(method);
311}
312
313void DeoptManager::PerformLimitedUndeoptimization(art::Thread* self, art::ArtMethod* method) {
314 ScopedDeoptimizationContext sdc(self, this);
315 art::Runtime::Current()->GetInstrumentation()->Undeoptimize(method);
316}
317
318void DeoptManager::PerformGlobalDeoptimization(art::Thread* self) {
319 ScopedDeoptimizationContext sdc(self, this);
320 art::Runtime::Current()->GetInstrumentation()->DeoptimizeEverything(
321 kDeoptManagerInstrumentationKey);
322}
323
324void DeoptManager::PerformGlobalUndeoptimization(art::Thread* self) {
325 ScopedDeoptimizationContext sdc(self, this);
326 art::Runtime::Current()->GetInstrumentation()->UndeoptimizeEverything(
327 kDeoptManagerInstrumentationKey);
328}
329
330
331void DeoptManager::RemoveDeoptimizationRequester() {
332 art::Thread* self = art::Thread::Current();
333 art::ScopedThreadStateChange sts(self, art::kSuspended);
334 deoptimization_status_lock_.ExclusiveLock(self);
335 DCHECK_GT(deopter_count_, 0u) << "Removing deoptimization requester without any being present";
336 deopter_count_--;
337 if (deopter_count_ == 0) {
338 ScopedDeoptimizationContext sdc(self, this);
339 // TODO Give this a real key.
340 art::Runtime::Current()->GetInstrumentation()->DisableDeoptimization("");
341 return;
342 } else {
343 deoptimization_status_lock_.ExclusiveUnlock(self);
344 }
345}
346
347void DeoptManager::AddDeoptimizationRequester() {
348 art::Thread* self = art::Thread::Current();
349 art::ScopedThreadStateChange stsc(self, art::kSuspended);
350 deoptimization_status_lock_.ExclusiveLock(self);
351 deopter_count_++;
352 if (deopter_count_ == 1) {
353 ScopedDeoptimizationContext sdc(self, this);
354 art::Runtime::Current()->GetInstrumentation()->EnableDeoptimization();
355 return;
356 } else {
357 deoptimization_status_lock_.ExclusiveUnlock(self);
358 }
359}
360
361void DeoptManager::DeoptimizeThread(art::Thread* target) {
362 art::Runtime::Current()->GetInstrumentation()->InstrumentThreadStack(target);
363}
364
Alex Light0e841182018-02-12 17:42:50 +0000365extern DeoptManager* gDeoptManager;
Alex Light0fa17862017-10-24 13:43:05 -0700366DeoptManager* DeoptManager::Get() {
Alex Light0e841182018-02-12 17:42:50 +0000367 return gDeoptManager;
Alex Light0fa17862017-10-24 13:43:05 -0700368}
369
370} // namespace openjdkjvmti