1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef ART_OPENJDKJVMTI_EVENTS_INL_H_ 18 #define ART_OPENJDKJVMTI_EVENTS_INL_H_ 19 20 #include <array> 21 #include <type_traits> 22 #include <tuple> 23 24 #include "base/mutex-inl.h" 25 #include "events.h" 26 #include "jni/jni_internal.h" 27 #include "nativehelper/scoped_local_ref.h" 28 #include "runtime-inl.h" 29 #include "scoped_thread_state_change-inl.h" 30 #include "stack.h" 31 #include "ti_breakpoint.h" 32 #include "ti_thread.h" 33 34 #include "art_jvmti.h" 35 36 namespace openjdkjvmti { 37 38 static inline ArtJvmtiEvent GetArtJvmtiEvent(ArtJvmTiEnv* env, jvmtiEvent e) { 39 if (UNLIKELY(e == JVMTI_EVENT_CLASS_FILE_LOAD_HOOK)) { 40 if (env->capabilities.can_retransform_classes) { 41 return ArtJvmtiEvent::kClassFileLoadHookRetransformable; 42 } else { 43 return ArtJvmtiEvent::kClassFileLoadHookNonRetransformable; 44 } 45 } else { 46 return static_cast<ArtJvmtiEvent>(e); 47 } 48 } 49 50 namespace impl { 51 52 // Helper for ensuring that the dispatch environment is sane. Events with JNIEnvs need to stash 53 // pending exceptions since they can cause new ones to be thrown. In accordance with the JVMTI 54 // specification we allow exceptions originating from events to overwrite the current exception, 55 // including exceptions originating from earlier events. 56 class ScopedEventDispatchEnvironment final : public art::ValueObject { 57 public: 58 ScopedEventDispatchEnvironment() : env_(nullptr), throw_(nullptr, nullptr) { 59 DCHECK_EQ(art::Thread::Current()->GetState(), art::ThreadState::kNative); 60 } 61 62 explicit ScopedEventDispatchEnvironment(JNIEnv* env) 63 : env_(env), 64 throw_(env_, env_->ExceptionOccurred()) { 65 DCHECK_EQ(art::Thread::Current()->GetState(), art::ThreadState::kNative); 66 // The spec doesn't say how much local data should be there, so we just give 128 which seems 67 // likely to be enough for most cases. 68 env_->PushLocalFrame(128); 69 env_->ExceptionClear(); 70 } 71 72 ~ScopedEventDispatchEnvironment() { 73 if (env_ != nullptr) { 74 if (throw_.get() != nullptr && !env_->ExceptionCheck()) { 75 // TODO It would be nice to add the overwritten exceptions to the suppressed exceptions list 76 // of the newest exception. 77 env_->Throw(throw_.get()); 78 } 79 env_->PopLocalFrame(nullptr); 80 } 81 DCHECK_EQ(art::Thread::Current()->GetState(), art::ThreadState::kNative); 82 } 83 84 private: 85 JNIEnv* env_; 86 ScopedLocalRef<jthrowable> throw_; 87 88 DISALLOW_COPY_AND_ASSIGN(ScopedEventDispatchEnvironment); 89 }; 90 91 // Infrastructure to achieve type safety for event dispatch. 92 93 #define FORALL_EVENT_TYPES(fn) \ 94 fn(VMInit, ArtJvmtiEvent::kVmInit) \ 95 fn(VMDeath, ArtJvmtiEvent::kVmDeath) \ 96 fn(ThreadStart, ArtJvmtiEvent::kThreadStart) \ 97 fn(ThreadEnd, ArtJvmtiEvent::kThreadEnd) \ 98 fn(ClassFileLoadHook, ArtJvmtiEvent::kClassFileLoadHookRetransformable) \ 99 fn(ClassFileLoadHook, ArtJvmtiEvent::kClassFileLoadHookNonRetransformable) \ 100 fn(ClassLoad, ArtJvmtiEvent::kClassLoad) \ 101 fn(ClassPrepare, ArtJvmtiEvent::kClassPrepare) \ 102 fn(VMStart, ArtJvmtiEvent::kVmStart) \ 103 fn(Exception, ArtJvmtiEvent::kException) \ 104 fn(ExceptionCatch, ArtJvmtiEvent::kExceptionCatch) \ 105 fn(SingleStep, ArtJvmtiEvent::kSingleStep) \ 106 fn(FramePop, ArtJvmtiEvent::kFramePop) \ 107 fn(Breakpoint, ArtJvmtiEvent::kBreakpoint) \ 108 fn(FieldAccess, ArtJvmtiEvent::kFieldAccess) \ 109 fn(FieldModification, ArtJvmtiEvent::kFieldModification) \ 110 fn(MethodEntry, ArtJvmtiEvent::kMethodEntry) \ 111 fn(MethodExit, ArtJvmtiEvent::kMethodExit) \ 112 fn(NativeMethodBind, ArtJvmtiEvent::kNativeMethodBind) \ 113 fn(CompiledMethodLoad, ArtJvmtiEvent::kCompiledMethodLoad) \ 114 fn(CompiledMethodUnload, ArtJvmtiEvent::kCompiledMethodUnload) \ 115 fn(DynamicCodeGenerated, ArtJvmtiEvent::kDynamicCodeGenerated) \ 116 fn(DataDumpRequest, ArtJvmtiEvent::kDataDumpRequest) \ 117 fn(MonitorWait, ArtJvmtiEvent::kMonitorWait) \ 118 fn(MonitorWaited, ArtJvmtiEvent::kMonitorWaited) \ 119 fn(MonitorContendedEnter, ArtJvmtiEvent::kMonitorContendedEnter) \ 120 fn(MonitorContendedEntered, ArtJvmtiEvent::kMonitorContendedEntered) \ 121 fn(ResourceExhausted, ArtJvmtiEvent::kResourceExhausted) \ 122 fn(GarbageCollectionStart, ArtJvmtiEvent::kGarbageCollectionStart) \ 123 fn(GarbageCollectionFinish, ArtJvmtiEvent::kGarbageCollectionFinish) \ 124 fn(ObjectFree, ArtJvmtiEvent::kObjectFree) \ 125 fn(VMObjectAlloc, ArtJvmtiEvent::kVmObjectAlloc) \ 126 fn(DdmPublishChunk, ArtJvmtiEvent::kDdmPublishChunk) 127 128 template <ArtJvmtiEvent kEvent> 129 struct EventFnType { 130 }; 131 132 #define EVENT_FN_TYPE(name, enum_name) \ 133 template <> \ 134 struct EventFnType<enum_name> { \ 135 using type = decltype(ArtJvmtiEventCallbacks().name); \ 136 }; 137 138 FORALL_EVENT_TYPES(EVENT_FN_TYPE) 139 140 #undef EVENT_FN_TYPE 141 142 #define MAKE_EVENT_HANDLER_FUNC(name, enum_name) \ 143 template<> \ 144 struct EventHandlerFunc<enum_name> { \ 145 using EventFnType = typename impl::EventFnType<enum_name>::type; \ 146 explicit EventHandlerFunc(ArtJvmTiEnv* env) \ 147 : env_(env), \ 148 fn_(env_->event_callbacks == nullptr ? nullptr : env_->event_callbacks->name) { } \ 149 \ 150 template <typename ...Args> \ 151 ALWAYS_INLINE \ 152 void ExecuteCallback(JNIEnv* jnienv, Args... args) const { \ 153 if (fn_ != nullptr) { \ 154 ScopedEventDispatchEnvironment sede(jnienv); \ 155 DoExecute(jnienv, args...); \ 156 } \ 157 } \ 158 \ 159 template <typename ...Args> \ 160 ALWAYS_INLINE \ 161 void ExecuteCallback(Args... args) const { \ 162 if (fn_ != nullptr) { \ 163 ScopedEventDispatchEnvironment sede; \ 164 DoExecute(args...); \ 165 } \ 166 } \ 167 \ 168 private: \ 169 template <typename ...Args> \ 170 ALWAYS_INLINE \ 171 inline void DoExecute(Args... args) const { \ 172 static_assert(std::is_same<EventFnType, void(*)(jvmtiEnv*, Args...)>::value, \ 173 "Unexpected different type of ExecuteCallback"); \ 174 fn_(env_, args...); \ 175 } \ 176 \ 177 public: \ 178 ArtJvmTiEnv* env_; \ 179 EventFnType fn_; \ 180 }; 181 182 FORALL_EVENT_TYPES(MAKE_EVENT_HANDLER_FUNC) 183 184 #undef MAKE_EVENT_HANDLER_FUNC 185 186 #undef FORALL_EVENT_TYPES 187 188 } // namespace impl 189 190 template <ArtJvmtiEvent kEvent, typename ...Args> 191 inline std::vector<impl::EventHandlerFunc<kEvent>> EventHandler::CollectEvents(art::Thread* thread, 192 Args... args) const { 193 art::ReaderMutexLock mu(thread, envs_lock_); 194 std::vector<impl::EventHandlerFunc<kEvent>> handlers; 195 for (ArtJvmTiEnv* env : envs) { 196 if (ShouldDispatch<kEvent>(env, thread, args...)) { 197 impl::EventHandlerFunc<kEvent> h(env); 198 handlers.push_back(h); 199 } 200 } 201 return handlers; 202 } 203 204 // C++ does not allow partial template function specialization. The dispatch for our separated 205 // ClassFileLoadHook event types is the same, so use this helper for code deduplication. 206 template <ArtJvmtiEvent kEvent> 207 inline void EventHandler::DispatchClassFileLoadHookEvent(art::Thread* thread, 208 JNIEnv* jnienv, 209 jclass class_being_redefined, 210 jobject loader, 211 const char* name, 212 jobject protection_domain, 213 jint class_data_len, 214 const unsigned char* class_data, 215 jint* new_class_data_len, 216 unsigned char** new_class_data) const { 217 art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative); 218 static_assert(kEvent == ArtJvmtiEvent::kClassFileLoadHookRetransformable || 219 kEvent == ArtJvmtiEvent::kClassFileLoadHookNonRetransformable, "Unsupported event"); 220 DCHECK(*new_class_data == nullptr); 221 jint current_len = class_data_len; 222 unsigned char* current_class_data = const_cast<unsigned char*>(class_data); 223 std::vector<impl::EventHandlerFunc<kEvent>> handlers = 224 CollectEvents<kEvent>(thread, 225 jnienv, 226 class_being_redefined, 227 loader, 228 name, 229 protection_domain, 230 class_data_len, 231 class_data, 232 new_class_data_len, 233 new_class_data); 234 ArtJvmTiEnv* last_env = nullptr; 235 for (const impl::EventHandlerFunc<kEvent>& event : handlers) { 236 jint new_len = 0; 237 unsigned char* new_data = nullptr; 238 ExecuteCallback<kEvent>(event, 239 jnienv, 240 class_being_redefined, 241 loader, 242 name, 243 protection_domain, 244 current_len, 245 static_cast<const unsigned char*>(current_class_data), 246 &new_len, 247 &new_data); 248 if (new_data != nullptr && new_data != current_class_data) { 249 // Destroy the data the last transformer made. We skip this if the previous state was the 250 // initial one since we don't know here which jvmtiEnv allocated it. 251 // NB Currently this doesn't matter since all allocations just go to malloc but in the 252 // future we might have jvmtiEnv's keep track of their allocations for leak-checking. 253 if (last_env != nullptr) { 254 last_env->Deallocate(current_class_data); 255 } 256 last_env = event.env_; 257 current_class_data = new_data; 258 current_len = new_len; 259 } 260 } 261 if (last_env != nullptr) { 262 *new_class_data_len = current_len; 263 *new_class_data = current_class_data; 264 } 265 } 266 267 // Our goal for DispatchEvent: Do not allow implicit type conversion. Types of ...args must match 268 // exactly the argument types of the corresponding Jvmti kEvent function pointer. 269 270 template <ArtJvmtiEvent kEvent, typename ...Args> 271 inline void EventHandler::DispatchEvent(art::Thread* thread, Args... args) const { 272 art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative); 273 static_assert(!std::is_same<JNIEnv*, 274 typename std::decay_t< 275 std::tuple_element_t<0, std::tuple<Args..., nullptr_t>>>>::value, 276 "Should be calling DispatchEvent with explicit JNIEnv* argument!"); 277 DCHECK(thread == nullptr || !thread->IsExceptionPending()); 278 std::vector<impl::EventHandlerFunc<kEvent>> events = CollectEvents<kEvent>(thread, args...); 279 for (auto event : events) { 280 ExecuteCallback<kEvent>(event, args...); 281 } 282 } 283 284 template <ArtJvmtiEvent kEvent, typename ...Args> 285 inline void EventHandler::DispatchEvent(art::Thread* thread, JNIEnv* jnienv, Args... args) const { 286 art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative); 287 std::vector<impl::EventHandlerFunc<kEvent>> events = CollectEvents<kEvent>(thread, 288 jnienv, 289 args...); 290 for (auto event : events) { 291 ExecuteCallback<kEvent>(event, jnienv, args...); 292 } 293 } 294 295 template <ArtJvmtiEvent kEvent, typename ...Args> 296 inline void EventHandler::DispatchEventOnEnv( 297 ArtJvmTiEnv* env, art::Thread* thread, JNIEnv* jnienv, Args... args) const { 298 DCHECK(env != nullptr); 299 if (ShouldDispatch<kEvent, JNIEnv*, Args...>(env, thread, jnienv, args...)) { 300 art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative); 301 impl::EventHandlerFunc<kEvent> func(env); 302 ExecuteCallback<kEvent>(func, jnienv, args...); 303 } 304 } 305 306 template <ArtJvmtiEvent kEvent, typename ...Args> 307 inline void EventHandler::DispatchEventOnEnv( 308 ArtJvmTiEnv* env, art::Thread* thread, Args... args) const { 309 static_assert(!std::is_same<JNIEnv*, 310 typename std::decay_t< 311 std::tuple_element_t<0, std::tuple<Args..., nullptr_t>>>>::value, 312 "Should be calling DispatchEventOnEnv with explicit JNIEnv* argument!"); 313 DCHECK(env != nullptr); 314 if (ShouldDispatch<kEvent, Args...>(env, thread, args...)) { 315 art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative); 316 impl::EventHandlerFunc<kEvent> func(env); 317 ExecuteCallback<kEvent>(func, args...); 318 } 319 } 320 321 template <ArtJvmtiEvent kEvent, typename ...Args> 322 inline void EventHandler::ExecuteCallback(impl::EventHandlerFunc<kEvent> handler, Args... args) { 323 handler.ExecuteCallback(args...); 324 } 325 326 template <ArtJvmtiEvent kEvent, typename ...Args> 327 inline void EventHandler::ExecuteCallback(impl::EventHandlerFunc<kEvent> handler, 328 JNIEnv* jnienv, 329 Args... args) { 330 handler.ExecuteCallback(jnienv, args...); 331 } 332 333 // Events that need custom logic for if we send the event but are otherwise normal. This includes 334 // the kBreakpoint, kFramePop, kFieldAccess, and kFieldModification events. 335 336 // Need to give custom specializations for Breakpoint since it needs to filter out which particular 337 // methods/dex_pcs agents get notified on. 338 template <> 339 inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kBreakpoint>( 340 ArtJvmTiEnv* env, 341 art::Thread* thread, 342 JNIEnv* jnienv ATTRIBUTE_UNUSED, 343 jthread jni_thread ATTRIBUTE_UNUSED, 344 jmethodID jmethod, 345 jlocation location) const { 346 art::ReaderMutexLock lk(art::Thread::Current(), env->event_info_mutex_); 347 art::ArtMethod* method = art::jni::DecodeArtMethod(jmethod); 348 return ShouldDispatchOnThread<ArtJvmtiEvent::kBreakpoint>(env, thread) && 349 env->breakpoints.find({method, location}) != env->breakpoints.end(); 350 } 351 352 template <> 353 inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFramePop>( 354 ArtJvmTiEnv* env, 355 art::Thread* thread, 356 JNIEnv* jnienv ATTRIBUTE_UNUSED, 357 jthread jni_thread ATTRIBUTE_UNUSED, 358 jmethodID jmethod ATTRIBUTE_UNUSED, 359 jboolean is_exception ATTRIBUTE_UNUSED, 360 const art::ShadowFrame* frame) const { 361 // Search for the frame. Do this before checking if we need to send the event so that we don't 362 // have to deal with use-after-free or the frames being reallocated later. 363 art::WriterMutexLock lk(art::Thread::Current(), env->event_info_mutex_); 364 return env->notify_frames.erase(frame) != 0 && 365 !frame->GetForcePopFrame() && 366 ShouldDispatchOnThread<ArtJvmtiEvent::kFramePop>(env, thread); 367 } 368 369 // Need to give custom specializations for FieldAccess and FieldModification since they need to 370 // filter out which particular fields agents want to get notified on. 371 // TODO The spec allows us to do shortcuts like only allow one agent to ever set these watches. This 372 // could make the system more performant. 373 template <> 374 inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFieldModification>( 375 ArtJvmTiEnv* env, 376 art::Thread* thread, 377 JNIEnv* jnienv ATTRIBUTE_UNUSED, 378 jthread jni_thread ATTRIBUTE_UNUSED, 379 jmethodID method ATTRIBUTE_UNUSED, 380 jlocation location ATTRIBUTE_UNUSED, 381 jclass field_klass ATTRIBUTE_UNUSED, 382 jobject object ATTRIBUTE_UNUSED, 383 jfieldID field, 384 char type_char ATTRIBUTE_UNUSED, 385 jvalue val ATTRIBUTE_UNUSED) const { 386 art::ReaderMutexLock lk(art::Thread::Current(), env->event_info_mutex_); 387 return ShouldDispatchOnThread<ArtJvmtiEvent::kFieldModification>(env, thread) && 388 env->modify_watched_fields.find( 389 art::jni::DecodeArtField(field)) != env->modify_watched_fields.end(); 390 } 391 392 template <> 393 inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFieldAccess>( 394 ArtJvmTiEnv* env, 395 art::Thread* thread, 396 JNIEnv* jnienv ATTRIBUTE_UNUSED, 397 jthread jni_thread ATTRIBUTE_UNUSED, 398 jmethodID method ATTRIBUTE_UNUSED, 399 jlocation location ATTRIBUTE_UNUSED, 400 jclass field_klass ATTRIBUTE_UNUSED, 401 jobject object ATTRIBUTE_UNUSED, 402 jfieldID field) const { 403 art::ReaderMutexLock lk(art::Thread::Current(), env->event_info_mutex_); 404 return ShouldDispatchOnThread<ArtJvmtiEvent::kFieldAccess>(env, thread) && 405 env->access_watched_fields.find( 406 art::jni::DecodeArtField(field)) != env->access_watched_fields.end(); 407 } 408 409 // Need to give custom specializations for FramePop since it needs to filter out which particular 410 // agents get the event. This specialization gets an extra argument so we can determine which (if 411 // any) environments have the frame pop. 412 // TODO It might be useful to use more template magic to have this only define ShouldDispatch or 413 // something. 414 template <> 415 inline void EventHandler::ExecuteCallback<ArtJvmtiEvent::kFramePop>( 416 impl::EventHandlerFunc<ArtJvmtiEvent::kFramePop> event, 417 JNIEnv* jnienv, 418 jthread jni_thread, 419 jmethodID jmethod, 420 jboolean is_exception, 421 const art::ShadowFrame* frame ATTRIBUTE_UNUSED) { 422 ExecuteCallback<ArtJvmtiEvent::kFramePop>(event, jnienv, jni_thread, jmethod, is_exception); 423 } 424 425 struct ScopedDisablePopFrame { 426 public: 427 explicit ScopedDisablePopFrame(art::Thread* thread) : thread_(thread) { 428 art::Locks::mutator_lock_->AssertSharedHeld(thread_); 429 art::MutexLock mu(thread_, *art::Locks::thread_list_lock_); 430 JvmtiGlobalTLSData* data = ThreadUtil::GetOrCreateGlobalTLSData(thread_); 431 current_top_frame_ = art::StackVisitor::ComputeNumFrames( 432 thread_, art::StackVisitor::StackWalkKind::kIncludeInlinedFrames); 433 old_disable_frame_pop_depth_ = data->disable_pop_frame_depth; 434 data->disable_pop_frame_depth = current_top_frame_; 435 DCHECK(old_disable_frame_pop_depth_ == JvmtiGlobalTLSData::kNoDisallowedPopFrame || 436 current_top_frame_ > old_disable_frame_pop_depth_) 437 << "old: " << old_disable_frame_pop_depth_ << " current: " << current_top_frame_; 438 } 439 440 ~ScopedDisablePopFrame() { 441 art::Locks::mutator_lock_->AssertSharedHeld(thread_); 442 art::MutexLock mu(thread_, *art::Locks::thread_list_lock_); 443 JvmtiGlobalTLSData* data = ThreadUtil::GetGlobalTLSData(thread_); 444 DCHECK_EQ(data->disable_pop_frame_depth, current_top_frame_); 445 data->disable_pop_frame_depth = old_disable_frame_pop_depth_; 446 } 447 448 private: 449 art::Thread* thread_; 450 size_t current_top_frame_; 451 size_t old_disable_frame_pop_depth_; 452 }; 453 // We want to prevent the use of PopFrame when reporting either of these events. 454 template <ArtJvmtiEvent kEvent> 455 inline void EventHandler::DispatchClassLoadOrPrepareEvent(art::Thread* thread, 456 JNIEnv* jnienv, 457 jthread jni_thread, 458 jclass klass) const { 459 ScopedDisablePopFrame sdpf(thread); 460 art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative); 461 std::vector<impl::EventHandlerFunc<kEvent>> events = CollectEvents<kEvent>(thread, 462 jnienv, 463 jni_thread, 464 klass); 465 466 for (auto event : events) { 467 ExecuteCallback<kEvent>(event, jnienv, jni_thread, klass); 468 } 469 } 470 471 template <> 472 inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassLoad>(art::Thread* thread, 473 JNIEnv* jnienv, 474 jthread jni_thread, 475 jclass klass) const { 476 DispatchClassLoadOrPrepareEvent<ArtJvmtiEvent::kClassLoad>(thread, jnienv, jni_thread, klass); 477 } 478 template <> 479 inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassPrepare>(art::Thread* thread, 480 JNIEnv* jnienv, 481 jthread jni_thread, 482 jclass klass) const { 483 DispatchClassLoadOrPrepareEvent<ArtJvmtiEvent::kClassPrepare>(thread, jnienv, jni_thread, klass); 484 } 485 486 // Need to give a custom specialization for NativeMethodBind since it has to deal with an out 487 // variable. 488 template <> 489 inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kNativeMethodBind>(art::Thread* thread, 490 JNIEnv* jnienv, 491 jthread jni_thread, 492 jmethodID method, 493 void* cur_method, 494 void** new_method) const { 495 art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative); 496 std::vector<impl::EventHandlerFunc<ArtJvmtiEvent::kNativeMethodBind>> events = 497 CollectEvents<ArtJvmtiEvent::kNativeMethodBind>(thread, 498 jnienv, 499 jni_thread, 500 method, 501 cur_method, 502 new_method); 503 *new_method = cur_method; 504 for (auto event : events) { 505 *new_method = cur_method; 506 ExecuteCallback<ArtJvmtiEvent::kNativeMethodBind>(event, 507 jnienv, 508 jni_thread, 509 method, 510 cur_method, 511 new_method); 512 if (*new_method != nullptr) { 513 cur_method = *new_method; 514 } 515 } 516 *new_method = cur_method; 517 } 518 519 // C++ does not allow partial template function specialization. The dispatch for our separated 520 // ClassFileLoadHook event types is the same, and in the DispatchClassFileLoadHookEvent helper. 521 // The following two DispatchEvent specializations dispatch to it. 522 template <> 523 inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>( 524 art::Thread* thread, 525 JNIEnv* jnienv, 526 jclass class_being_redefined, 527 jobject loader, 528 const char* name, 529 jobject protection_domain, 530 jint class_data_len, 531 const unsigned char* class_data, 532 jint* new_class_data_len, 533 unsigned char** new_class_data) const { 534 return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>( 535 thread, 536 jnienv, 537 class_being_redefined, 538 loader, 539 name, 540 protection_domain, 541 class_data_len, 542 class_data, 543 new_class_data_len, 544 new_class_data); 545 } 546 547 template <> 548 inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>( 549 art::Thread* thread, 550 JNIEnv* jnienv, 551 jclass class_being_redefined, 552 jobject loader, 553 const char* name, 554 jobject protection_domain, 555 jint class_data_len, 556 const unsigned char* class_data, 557 jint* new_class_data_len, 558 unsigned char** new_class_data) const { 559 return DispatchClassFileLoadHookEvent<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>( 560 thread, 561 jnienv, 562 class_being_redefined, 563 loader, 564 name, 565 protection_domain, 566 class_data_len, 567 class_data, 568 new_class_data_len, 569 new_class_data); 570 } 571 572 template <ArtJvmtiEvent kEvent> 573 inline bool EventHandler::ShouldDispatchOnThread(ArtJvmTiEnv* env, art::Thread* thread) const { 574 bool dispatch = env->event_masks.global_event_mask.Test(kEvent); 575 576 if (!dispatch && thread != nullptr && env->event_masks.unioned_thread_event_mask.Test(kEvent)) { 577 EventMask* mask = env->event_masks.GetEventMaskOrNull(thread); 578 dispatch = mask != nullptr && mask->Test(kEvent); 579 } 580 return dispatch; 581 } 582 583 template <ArtJvmtiEvent kEvent, typename ...Args> 584 inline bool EventHandler::ShouldDispatch(ArtJvmTiEnv* env, 585 art::Thread* thread, 586 Args... args ATTRIBUTE_UNUSED) const { 587 static_assert(std::is_same<typename impl::EventFnType<kEvent>::type, 588 void(*)(jvmtiEnv*, Args...)>::value, 589 "Unexpected different type of shouldDispatch"); 590 591 return ShouldDispatchOnThread<kEvent>(env, thread); 592 } 593 594 inline void EventHandler::RecalculateGlobalEventMask(ArtJvmtiEvent event) { 595 art::WriterMutexLock mu(art::Thread::Current(), envs_lock_); 596 RecalculateGlobalEventMaskLocked(event); 597 } 598 599 inline void EventHandler::RecalculateGlobalEventMaskLocked(ArtJvmtiEvent event) { 600 bool union_value = false; 601 for (const ArtJvmTiEnv* stored_env : envs) { 602 if (stored_env == nullptr) { 603 continue; 604 } 605 union_value |= stored_env->event_masks.global_event_mask.Test(event); 606 union_value |= stored_env->event_masks.unioned_thread_event_mask.Test(event); 607 if (union_value) { 608 break; 609 } 610 } 611 global_mask.Set(event, union_value); 612 } 613 614 inline bool EventHandler::NeedsEventUpdate(ArtJvmTiEnv* env, 615 const jvmtiCapabilities& caps, 616 bool added) { 617 ArtJvmtiEvent event = added ? ArtJvmtiEvent::kClassFileLoadHookNonRetransformable 618 : ArtJvmtiEvent::kClassFileLoadHookRetransformable; 619 return (added && caps.can_access_local_variables == 1) || 620 caps.can_generate_breakpoint_events == 1 || 621 caps.can_pop_frame == 1 || 622 (caps.can_retransform_classes == 1 && 623 IsEventEnabledAnywhere(event) && 624 env->event_masks.IsEnabledAnywhere(event)); 625 } 626 627 inline void EventHandler::HandleChangedCapabilities(ArtJvmTiEnv* env, 628 const jvmtiCapabilities& caps, 629 bool added) { 630 if (UNLIKELY(NeedsEventUpdate(env, caps, added))) { 631 env->event_masks.HandleChangedCapabilities(caps, added); 632 if (caps.can_retransform_classes == 1) { 633 RecalculateGlobalEventMask(ArtJvmtiEvent::kClassFileLoadHookRetransformable); 634 RecalculateGlobalEventMask(ArtJvmtiEvent::kClassFileLoadHookNonRetransformable); 635 } 636 if (added && caps.can_access_local_variables == 1) { 637 HandleLocalAccessCapabilityAdded(); 638 } 639 if (caps.can_generate_breakpoint_events == 1) { 640 HandleBreakpointEventsChanged(added); 641 } 642 if (caps.can_pop_frame == 1 && added) { 643 // TODO We should keep track of how many of these have been enabled and remove it if there are 644 // no more possible users. This isn't expected to be too common. 645 art::Runtime::Current()->SetNonStandardExitsEnabled(); 646 } 647 } 648 } 649 650 } // namespace openjdkjvmti 651 652 #endif // ART_OPENJDKJVMTI_EVENTS_INL_H_ 653