1 /* 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" 40 #include "dex/dex_file_annotations.h" 41 #include "dex/modifiers.h" 42 #include "events-inl.h" 43 #include "jit/jit.h" 44 #include "jni_internal.h" 45 #include "mirror/class-inl.h" 46 #include "mirror/object_array-inl.h" 47 #include "nativehelper/scoped_local_ref.h" 48 #include "runtime_callbacks.h" 49 #include "scoped_thread_state_change-inl.h" 50 #include "thread-current-inl.h" 51 #include "thread_list.h" 52 #include "ti_phase.h" 53 54 namespace openjdkjvmti { 55 56 // TODO We should make this much more selective in the future so we only return true when we 57 // actually care about the method at this time (ie active frames had locals changed). For now we 58 // just assume that if anything has changed any frame's locals we care about all methods. If nothing 59 // has we only care about methods with active breakpoints on them. In the future we should probably 60 // rewrite all of this to instead do this at the ShadowFrame or thread granularity. 61 bool JvmtiMethodInspectionCallback::IsMethodBeingInspected(art::ArtMethod* method) { 62 // Non-java-debuggable runtimes we need to assume that any method might not be debuggable and 63 // therefore potentially being inspected (due to inlines). If we are debuggable we rely hard on 64 // inlining not being done since we don't keep track of which methods get inlined where and simply 65 // look to see if the method is breakpointed. 66 return !art::Runtime::Current()->IsJavaDebuggable() || 67 manager_->HaveLocalsChanged() || 68 manager_->MethodHasBreakpoints(method); 69 } 70 71 bool JvmtiMethodInspectionCallback::IsMethodSafeToJit(art::ArtMethod* method) { 72 return !manager_->MethodHasBreakpoints(method); 73 } 74 75 bool JvmtiMethodInspectionCallback::MethodNeedsDebugVersion( 76 art::ArtMethod* method ATTRIBUTE_UNUSED) { 77 return true; 78 } 79 80 DeoptManager::DeoptManager() 81 : deoptimization_status_lock_("JVMTI_DeoptimizationStatusLock", 82 static_cast<art::LockLevel>( 83 art::LockLevel::kClassLinkerClassesLock + 1)), 84 deoptimization_condition_("JVMTI_DeoptimizationCondition", deoptimization_status_lock_), 85 performing_deoptimization_(false), 86 global_deopt_count_(0), 87 deopter_count_(0), 88 breakpoint_status_lock_("JVMTI_BreakpointStatusLock", 89 static_cast<art::LockLevel>(art::LockLevel::kAbortLock + 1)), 90 inspection_callback_(this), 91 set_local_variable_called_(false) { } 92 93 void DeoptManager::Setup() { 94 art::ScopedThreadStateChange stsc(art::Thread::Current(), 95 art::ThreadState::kWaitingForDebuggerToAttach); 96 art::ScopedSuspendAll ssa("Add method Inspection Callback"); 97 art::RuntimeCallbacks* callbacks = art::Runtime::Current()->GetRuntimeCallbacks(); 98 callbacks->AddMethodInspectionCallback(&inspection_callback_); 99 } 100 101 void DeoptManager::Shutdown() { 102 art::ScopedThreadStateChange stsc(art::Thread::Current(), 103 art::ThreadState::kWaitingForDebuggerToAttach); 104 art::ScopedSuspendAll ssa("remove method Inspection Callback"); 105 art::RuntimeCallbacks* callbacks = art::Runtime::Current()->GetRuntimeCallbacks(); 106 callbacks->RemoveMethodInspectionCallback(&inspection_callback_); 107 } 108 109 void DeoptManager::FinishSetup() { 110 art::Thread* self = art::Thread::Current(); 111 art::MutexLock mu(self, deoptimization_status_lock_); 112 113 art::Runtime* runtime = art::Runtime::Current(); 114 // See if we need to do anything. 115 if (!runtime->IsJavaDebuggable()) { 116 // See if we can enable all JVMTI functions. If this is false, only kArtTiVersion agents can be 117 // retrieved and they will all be best-effort. 118 if (PhaseUtil::GetPhaseUnchecked() == JVMTI_PHASE_ONLOAD) { 119 // We are still early enough to change the compiler options and get full JVMTI support. 120 LOG(INFO) << "Openjdkjvmti plugin loaded on a non-debuggable runtime. Changing runtime to " 121 << "debuggable state. Please pass '--debuggable' to dex2oat and " 122 << "'-Xcompiler-option --debuggable' to dalvikvm in the future."; 123 DCHECK(runtime->GetJit() == nullptr) << "Jit should not be running yet!"; 124 runtime->AddCompilerOption("--debuggable"); 125 runtime->SetJavaDebuggable(true); 126 } else { 127 LOG(WARNING) << "Openjdkjvmti plugin was loaded on a non-debuggable Runtime. Plugin was " 128 << "loaded too late to change runtime state to DEBUGGABLE. Only kArtTiVersion " 129 << "(0x" << std::hex << kArtTiVersion << ") environments are available. Some " 130 << "functionality might not work properly."; 131 if (runtime->GetJit() == nullptr && 132 runtime->GetJITOptions()->UseJitCompilation() && 133 !runtime->GetInstrumentation()->IsForcedInterpretOnly()) { 134 // If we don't have a jit we should try to start the jit for performance reasons. We only 135 // need to do this for late attach on non-debuggable processes because for debuggable 136 // processes we already rely on jit and we cannot force this jit to start if we are still in 137 // OnLoad since the runtime hasn't started up sufficiently. This is only expected to happen 138 // on userdebug/eng builds. 139 LOG(INFO) << "Attempting to start jit for openjdkjvmti plugin."; 140 runtime->CreateJit(); 141 if (runtime->GetJit() == nullptr) { 142 LOG(WARNING) << "Could not start jit for openjdkjvmti plugin. This process might be " 143 << "quite slow as it is running entirely in the interpreter. Try running " 144 << "'setenforce 0' and restarting this process."; 145 } 146 } 147 } 148 runtime->DeoptimizeBootImage(); 149 } 150 } 151 152 bool DeoptManager::MethodHasBreakpoints(art::ArtMethod* method) { 153 art::MutexLock lk(art::Thread::Current(), breakpoint_status_lock_); 154 return MethodHasBreakpointsLocked(method); 155 } 156 157 bool DeoptManager::MethodHasBreakpointsLocked(art::ArtMethod* method) { 158 auto elem = breakpoint_status_.find(method); 159 return elem != breakpoint_status_.end() && elem->second != 0; 160 } 161 162 void DeoptManager::RemoveDeoptimizeAllMethods() { 163 art::Thread* self = art::Thread::Current(); 164 art::ScopedThreadSuspension sts(self, art::kSuspended); 165 deoptimization_status_lock_.ExclusiveLock(self); 166 RemoveDeoptimizeAllMethodsLocked(self); 167 } 168 169 void DeoptManager::AddDeoptimizeAllMethods() { 170 art::Thread* self = art::Thread::Current(); 171 art::ScopedThreadSuspension sts(self, art::kSuspended); 172 deoptimization_status_lock_.ExclusiveLock(self); 173 AddDeoptimizeAllMethodsLocked(self); 174 } 175 176 void DeoptManager::AddMethodBreakpoint(art::ArtMethod* method) { 177 DCHECK(method->IsInvokable()); 178 DCHECK(!method->IsProxyMethod()) << method->PrettyMethod(); 179 DCHECK(!method->IsNative()) << method->PrettyMethod(); 180 181 art::Thread* self = art::Thread::Current(); 182 method = method->GetCanonicalMethod(); 183 bool is_default = method->IsDefault(); 184 185 art::ScopedThreadSuspension sts(self, art::kSuspended); 186 deoptimization_status_lock_.ExclusiveLock(self); 187 { 188 breakpoint_status_lock_.ExclusiveLock(self); 189 190 DCHECK_GT(deopter_count_, 0u) << "unexpected deotpimization request"; 191 192 if (MethodHasBreakpointsLocked(method)) { 193 // Don't need to do anything extra. 194 breakpoint_status_[method]++; 195 // Another thread might be deoptimizing the very method we just added new breakpoints for. 196 // Wait for any deopts to finish before moving on. 197 breakpoint_status_lock_.ExclusiveUnlock(self); 198 WaitForDeoptimizationToFinish(self); 199 return; 200 } 201 breakpoint_status_[method] = 1; 202 breakpoint_status_lock_.ExclusiveUnlock(self); 203 } 204 auto instrumentation = art::Runtime::Current()->GetInstrumentation(); 205 if (instrumentation->IsForcedInterpretOnly()) { 206 // We are already interpreting everything so no need to do anything. 207 deoptimization_status_lock_.ExclusiveUnlock(self); 208 return; 209 } else if (is_default) { 210 AddDeoptimizeAllMethodsLocked(self); 211 } else { 212 PerformLimitedDeoptimization(self, method); 213 } 214 } 215 216 void DeoptManager::RemoveMethodBreakpoint(art::ArtMethod* method) { 217 DCHECK(method->IsInvokable()) << method->PrettyMethod(); 218 DCHECK(!method->IsProxyMethod()) << method->PrettyMethod(); 219 DCHECK(!method->IsNative()) << method->PrettyMethod(); 220 221 art::Thread* self = art::Thread::Current(); 222 method = method->GetCanonicalMethod(); 223 bool is_default = method->IsDefault(); 224 225 art::ScopedThreadSuspension sts(self, art::kSuspended); 226 // Ideally we should do a ScopedSuspendAll right here to get the full mutator_lock_ that we might 227 // need but since that is very heavy we will instead just use a condition variable to make sure we 228 // don't race with ourselves. 229 deoptimization_status_lock_.ExclusiveLock(self); 230 bool is_last_breakpoint; 231 { 232 art::MutexLock mu(self, breakpoint_status_lock_); 233 234 DCHECK_GT(deopter_count_, 0u) << "unexpected deotpimization request"; 235 DCHECK(MethodHasBreakpointsLocked(method)) << "Breakpoint on a method was removed without " 236 << "breakpoints present!"; 237 breakpoint_status_[method] -= 1; 238 is_last_breakpoint = (breakpoint_status_[method] == 0); 239 } 240 auto instrumentation = art::Runtime::Current()->GetInstrumentation(); 241 if (UNLIKELY(instrumentation->IsForcedInterpretOnly())) { 242 // We don't need to do anything since we are interpreting everything anyway. 243 deoptimization_status_lock_.ExclusiveUnlock(self); 244 return; 245 } else if (is_last_breakpoint) { 246 if (UNLIKELY(is_default)) { 247 RemoveDeoptimizeAllMethodsLocked(self); 248 } else { 249 PerformLimitedUndeoptimization(self, method); 250 } 251 } else { 252 // Another thread might be deoptimizing the very methods we just removed breakpoints from. Wait 253 // for any deopts to finish before moving on. 254 WaitForDeoptimizationToFinish(self); 255 } 256 } 257 258 void DeoptManager::WaitForDeoptimizationToFinishLocked(art::Thread* self) { 259 while (performing_deoptimization_) { 260 deoptimization_condition_.Wait(self); 261 } 262 } 263 264 void DeoptManager::WaitForDeoptimizationToFinish(art::Thread* self) { 265 WaitForDeoptimizationToFinishLocked(self); 266 deoptimization_status_lock_.ExclusiveUnlock(self); 267 } 268 269 class ScopedDeoptimizationContext : public art::ValueObject { 270 public: 271 ScopedDeoptimizationContext(art::Thread* self, DeoptManager* deopt) 272 RELEASE(deopt->deoptimization_status_lock_) 273 ACQUIRE(art::Locks::mutator_lock_) 274 ACQUIRE(art::Roles::uninterruptible_) 275 : self_(self), deopt_(deopt), uninterruptible_cause_(nullptr) { 276 deopt_->WaitForDeoptimizationToFinishLocked(self_); 277 DCHECK(!deopt->performing_deoptimization_) 278 << "Already performing deoptimization on another thread!"; 279 // Use performing_deoptimization_ to keep track of the lock. 280 deopt_->performing_deoptimization_ = true; 281 deopt_->deoptimization_status_lock_.Unlock(self_); 282 art::Runtime::Current()->GetThreadList()->SuspendAll("JMVTI Deoptimizing methods", 283 /*long_suspend*/ false); 284 uninterruptible_cause_ = self_->StartAssertNoThreadSuspension("JVMTI deoptimizing methods"); 285 } 286 287 ~ScopedDeoptimizationContext() 288 RELEASE(art::Locks::mutator_lock_) 289 RELEASE(art::Roles::uninterruptible_) { 290 // Can be suspended again. 291 self_->EndAssertNoThreadSuspension(uninterruptible_cause_); 292 // Release the mutator lock. 293 art::Runtime::Current()->GetThreadList()->ResumeAll(); 294 // Let other threads know it's fine to proceed. 295 art::MutexLock lk(self_, deopt_->deoptimization_status_lock_); 296 deopt_->performing_deoptimization_ = false; 297 deopt_->deoptimization_condition_.Broadcast(self_); 298 } 299 300 private: 301 art::Thread* self_; 302 DeoptManager* deopt_; 303 const char* uninterruptible_cause_; 304 }; 305 306 void DeoptManager::AddDeoptimizeAllMethodsLocked(art::Thread* self) { 307 global_deopt_count_++; 308 if (global_deopt_count_ == 1) { 309 PerformGlobalDeoptimization(self); 310 } else { 311 WaitForDeoptimizationToFinish(self); 312 } 313 } 314 315 void DeoptManager::RemoveDeoptimizeAllMethodsLocked(art::Thread* self) { 316 DCHECK_GT(global_deopt_count_, 0u) << "Request to remove non-existent global deoptimization!"; 317 global_deopt_count_--; 318 if (global_deopt_count_ == 0) { 319 PerformGlobalUndeoptimization(self); 320 } else { 321 WaitForDeoptimizationToFinish(self); 322 } 323 } 324 325 void DeoptManager::PerformLimitedDeoptimization(art::Thread* self, art::ArtMethod* method) { 326 ScopedDeoptimizationContext sdc(self, this); 327 art::Runtime::Current()->GetInstrumentation()->Deoptimize(method); 328 } 329 330 void DeoptManager::PerformLimitedUndeoptimization(art::Thread* self, art::ArtMethod* method) { 331 ScopedDeoptimizationContext sdc(self, this); 332 art::Runtime::Current()->GetInstrumentation()->Undeoptimize(method); 333 } 334 335 void DeoptManager::PerformGlobalDeoptimization(art::Thread* self) { 336 ScopedDeoptimizationContext sdc(self, this); 337 art::Runtime::Current()->GetInstrumentation()->DeoptimizeEverything( 338 kDeoptManagerInstrumentationKey); 339 } 340 341 void DeoptManager::PerformGlobalUndeoptimization(art::Thread* self) { 342 ScopedDeoptimizationContext sdc(self, this); 343 art::Runtime::Current()->GetInstrumentation()->UndeoptimizeEverything( 344 kDeoptManagerInstrumentationKey); 345 } 346 347 348 void DeoptManager::RemoveDeoptimizationRequester() { 349 art::Thread* self = art::Thread::Current(); 350 art::ScopedThreadStateChange sts(self, art::kSuspended); 351 deoptimization_status_lock_.ExclusiveLock(self); 352 DCHECK_GT(deopter_count_, 0u) << "Removing deoptimization requester without any being present"; 353 deopter_count_--; 354 if (deopter_count_ == 0) { 355 ScopedDeoptimizationContext sdc(self, this); 356 // TODO Give this a real key. 357 art::Runtime::Current()->GetInstrumentation()->DisableDeoptimization(""); 358 return; 359 } else { 360 deoptimization_status_lock_.ExclusiveUnlock(self); 361 } 362 } 363 364 void DeoptManager::AddDeoptimizationRequester() { 365 art::Thread* self = art::Thread::Current(); 366 art::ScopedThreadStateChange stsc(self, art::kSuspended); 367 deoptimization_status_lock_.ExclusiveLock(self); 368 deopter_count_++; 369 if (deopter_count_ == 1) { 370 ScopedDeoptimizationContext sdc(self, this); 371 art::Runtime::Current()->GetInstrumentation()->EnableDeoptimization(); 372 return; 373 } else { 374 deoptimization_status_lock_.ExclusiveUnlock(self); 375 } 376 } 377 378 void DeoptManager::DeoptimizeThread(art::Thread* target) { 379 art::Runtime::Current()->GetInstrumentation()->InstrumentThreadStack(target); 380 } 381 382 extern DeoptManager* gDeoptManager; 383 DeoptManager* DeoptManager::Get() { 384 return gDeoptManager; 385 } 386 387 } // namespace openjdkjvmti 388