1 /* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef PANDA_RUNTIME_INCLUDE_RUNTIME_NOTIFICATION_H_ 17 #define PANDA_RUNTIME_INCLUDE_RUNTIME_NOTIFICATION_H_ 18 19 #include <optional> 20 #include <string_view> 21 22 #include "libpandabase/os/mutex.h" 23 #include "runtime/include/locks.h" 24 #include "runtime/include/mem/panda_containers.h" 25 #include "runtime/include/mem/panda_string.h" 26 #include "runtime/include/runtime.h" 27 #include "runtime/include/managed_thread.h" 28 29 namespace panda { 30 31 class Method; 32 class Class; 33 class Rendezvous; 34 35 class RuntimeListener { 36 public: 37 RuntimeListener() = default; 38 virtual ~RuntimeListener() = default; 39 DEFAULT_COPY_SEMANTIC(RuntimeListener); 40 DEFAULT_MOVE_SEMANTIC(RuntimeListener); 41 LoadModule(std::string_view name)42 virtual void LoadModule([[maybe_unused]] std::string_view name) {} 43 ThreadStart(ManagedThread::ThreadId thread_id)44 virtual void ThreadStart([[maybe_unused]] ManagedThread::ThreadId thread_id) {} ThreadEnd(ManagedThread::ThreadId thread_id)45 virtual void ThreadEnd([[maybe_unused]] ManagedThread::ThreadId thread_id) {} 46 BytecodePcChanged(ManagedThread * thread,Method * method,uint32_t bc_offset)47 virtual void BytecodePcChanged([[maybe_unused]] ManagedThread *thread, [[maybe_unused]] Method *method, 48 [[maybe_unused]] uint32_t bc_offset) 49 { 50 } 51 GarbageCollectorStart()52 virtual void GarbageCollectorStart() {} GarbageCollectorFinish()53 virtual void GarbageCollectorFinish() {} 54 ExceptionCatch(const ManagedThread * thread,const Method * method,uint32_t bc_offset)55 virtual void ExceptionCatch([[maybe_unused]] const ManagedThread *thread, [[maybe_unused]] const Method *method, 56 [[maybe_unused]] uint32_t bc_offset) 57 { 58 } 59 VmStart()60 virtual void VmStart() {} VmInitialization(ManagedThread::ThreadId thread_id)61 virtual void VmInitialization([[maybe_unused]] ManagedThread::ThreadId thread_id) {} VmDeath()62 virtual void VmDeath() {} 63 MethodEntry(ManagedThread * thread,Method * method)64 virtual void MethodEntry([[maybe_unused]] ManagedThread *thread, [[maybe_unused]] Method *method) {} MethodExit(ManagedThread * thread,Method * method)65 virtual void MethodExit([[maybe_unused]] ManagedThread *thread, [[maybe_unused]] Method *method) {} 66 ClassLoad(Class * klass)67 virtual void ClassLoad([[maybe_unused]] Class *klass) {} ClassPrepare(Class * klass)68 virtual void ClassPrepare([[maybe_unused]] Class *klass) {} 69 MonitorWait(ObjectHeader * object,int64_t timeout)70 virtual void MonitorWait([[maybe_unused]] ObjectHeader *object, [[maybe_unused]] int64_t timeout) {} MonitorWaited(ObjectHeader * object,bool timed_out)71 virtual void MonitorWaited([[maybe_unused]] ObjectHeader *object, [[maybe_unused]] bool timed_out) {} MonitorContendedEnter(ObjectHeader * object)72 virtual void MonitorContendedEnter([[maybe_unused]] ObjectHeader *object) {} MonitorContendedEntered(ObjectHeader * object)73 virtual void MonitorContendedEntered([[maybe_unused]] ObjectHeader *object) {} 74 ObjectAlloc(BaseClass * klass,ObjectHeader * object,ManagedThread * thread,size_t size)75 virtual void ObjectAlloc([[maybe_unused]] BaseClass *klass, [[maybe_unused]] ObjectHeader *object, 76 [[maybe_unused]] ManagedThread *thread, [[maybe_unused]] size_t size) 77 { 78 } 79 }; 80 81 class DdmListener { 82 public: 83 DdmListener() = default; 84 virtual ~DdmListener() = default; 85 DEFAULT_COPY_SEMANTIC(DdmListener); 86 DEFAULT_MOVE_SEMANTIC(DdmListener); 87 88 virtual void DdmPublishChunk(uint32_t type, const Span<const uint8_t> &data) = 0; 89 }; 90 91 class DebuggerListener { 92 public: 93 DebuggerListener() = default; 94 virtual ~DebuggerListener() = default; 95 DEFAULT_COPY_SEMANTIC(DebuggerListener); 96 DEFAULT_MOVE_SEMANTIC(DebuggerListener); 97 98 virtual void StartDebugger() = 0; 99 virtual void StopDebugger() = 0; 100 virtual bool IsDebuggerConfigured() = 0; 101 }; 102 103 class RuntimeNotificationManager { 104 public: 105 enum Event : uint32_t { 106 BYTECODE_PC_CHANGED = 0x01, 107 LOAD_MODULE = 0x02, 108 THREAD_EVENTS = 0x04, 109 GARBAGE_COLLECTOR_EVENTS = 0x08, 110 EXCEPTION_EVENTS = 0x10, 111 VM_EVENTS = 0x20, 112 METHOD_EVENTS = 0x40, 113 CLASS_EVENTS = 0x80, 114 MONITOR_EVENTS = 0x100, 115 ALLOCATION_EVENTS = 0x200, 116 ALL = 0xFFFFFFFF 117 }; 118 RuntimeNotificationManager(mem::AllocatorPtr<mem::AllocatorPurpose::ALLOCATOR_PURPOSE_INTERNAL> allocator)119 explicit RuntimeNotificationManager(mem::AllocatorPtr<mem::AllocatorPurpose::ALLOCATOR_PURPOSE_INTERNAL> allocator) 120 : bytecode_pc_listeners_(allocator->Adapter()), 121 load_module_listeners_(allocator->Adapter()), 122 thread_events_listeners_(allocator->Adapter()), 123 garbage_collector_listeners_(allocator->Adapter()), 124 exception_listeners_(allocator->Adapter()), 125 vm_events_listeners_(allocator->Adapter()), 126 method_listeners_(allocator->Adapter()), 127 class_listeners_(allocator->Adapter()), 128 monitor_listeners_(allocator->Adapter()), 129 ddm_listeners_(allocator->Adapter()) 130 { 131 } 132 ~RuntimeNotificationManager() = default; 133 NO_COPY_SEMANTIC(RuntimeNotificationManager); 134 NO_MOVE_SEMANTIC(RuntimeNotificationManager); 135 AddListener(RuntimeListener * listener,uint32_t event_mask)136 void AddListener(RuntimeListener *listener, uint32_t event_mask) 137 { 138 ScopedSuspendAllThreads ssat(rendezvous_); 139 AddListenerIfMatches(listener, event_mask, &bytecode_pc_listeners_, Event::BYTECODE_PC_CHANGED, 140 &has_bytecode_pc_listeners_); 141 142 AddListenerIfMatches(listener, event_mask, &load_module_listeners_, Event::LOAD_MODULE, 143 &has_load_module_listeners_); 144 145 AddListenerIfMatches(listener, event_mask, &thread_events_listeners_, Event::THREAD_EVENTS, 146 &has_thread_events_listeners_); 147 148 AddListenerIfMatches(listener, event_mask, &garbage_collector_listeners_, Event::GARBAGE_COLLECTOR_EVENTS, 149 &has_garbage_collector_listeners_); 150 151 AddListenerIfMatches(listener, event_mask, &exception_listeners_, Event::EXCEPTION_EVENTS, 152 &has_exception_listeners_); 153 154 AddListenerIfMatches(listener, event_mask, &vm_events_listeners_, Event::VM_EVENTS, &has_vm_events_listeners_); 155 156 AddListenerIfMatches(listener, event_mask, &method_listeners_, Event::METHOD_EVENTS, &has_method_listeners_); 157 158 AddListenerIfMatches(listener, event_mask, &class_listeners_, Event::CLASS_EVENTS, &has_class_listeners_); 159 160 AddListenerIfMatches(listener, event_mask, &monitor_listeners_, Event::MONITOR_EVENTS, &has_monitor_listeners_); 161 162 AddListenerIfMatches(listener, event_mask, &allocation_listeners_, Event::ALLOCATION_EVENTS, 163 &has_allocation_listeners_); 164 } 165 RemoveListener(RuntimeListener * listener,uint32_t event_mask)166 void RemoveListener(RuntimeListener *listener, uint32_t event_mask) 167 { 168 ScopedSuspendAllThreads ssat(rendezvous_); 169 RemoveListenerIfMatches(listener, event_mask, &bytecode_pc_listeners_, Event::BYTECODE_PC_CHANGED, 170 &has_bytecode_pc_listeners_); 171 172 RemoveListenerIfMatches(listener, event_mask, &load_module_listeners_, Event::LOAD_MODULE, 173 &has_load_module_listeners_); 174 175 RemoveListenerIfMatches(listener, event_mask, &thread_events_listeners_, Event::THREAD_EVENTS, 176 &has_thread_events_listeners_); 177 178 RemoveListenerIfMatches(listener, event_mask, &garbage_collector_listeners_, Event::GARBAGE_COLLECTOR_EVENTS, 179 &has_garbage_collector_listeners_); 180 181 RemoveListenerIfMatches(listener, event_mask, &exception_listeners_, Event::EXCEPTION_EVENTS, 182 &has_exception_listeners_); 183 184 RemoveListenerIfMatches(listener, event_mask, &vm_events_listeners_, Event::VM_EVENTS, 185 &has_vm_events_listeners_); 186 187 RemoveListenerIfMatches(listener, event_mask, &method_listeners_, Event::METHOD_EVENTS, &has_method_listeners_); 188 189 RemoveListenerIfMatches(listener, event_mask, &class_listeners_, Event::CLASS_EVENTS, &has_class_listeners_); 190 191 RemoveListenerIfMatches(listener, event_mask, &monitor_listeners_, Event::MONITOR_EVENTS, 192 &has_monitor_listeners_); 193 194 RemoveListenerIfMatches(listener, event_mask, &allocation_listeners_, Event::ALLOCATION_EVENTS, 195 &has_allocation_listeners_); 196 } 197 LoadModuleEvent(std::string_view name)198 void LoadModuleEvent(std::string_view name) 199 { 200 if (UNLIKELY(has_load_module_listeners_)) { 201 for (auto *listener : load_module_listeners_) { 202 if (listener != nullptr) { 203 listener->LoadModule(name); 204 } 205 } 206 } 207 } 208 ThreadStartEvent(ManagedThread::ThreadId thread_id)209 void ThreadStartEvent(ManagedThread::ThreadId thread_id) 210 { 211 if (UNLIKELY(has_thread_events_listeners_)) { 212 for (auto *listener : thread_events_listeners_) { 213 if (listener != nullptr) { 214 listener->ThreadStart(thread_id); 215 } 216 } 217 } 218 } 219 ThreadEndEvent(ManagedThread::ThreadId thread_id)220 void ThreadEndEvent(ManagedThread::ThreadId thread_id) 221 { 222 if (UNLIKELY(has_thread_events_listeners_)) { 223 for (auto *listener : thread_events_listeners_) { 224 if (listener != nullptr) { 225 listener->ThreadEnd(thread_id); 226 } 227 } 228 } 229 } 230 BytecodePcChangedEvent(ManagedThread * thread,Method * method,uint32_t bc_offset)231 void BytecodePcChangedEvent(ManagedThread *thread, Method *method, uint32_t bc_offset) 232 { 233 if (UNLIKELY(has_bytecode_pc_listeners_)) { 234 for (auto *listener : bytecode_pc_listeners_) { 235 if (listener != nullptr) { 236 listener->BytecodePcChanged(thread, method, bc_offset); 237 } 238 } 239 } 240 } 241 GarbageCollectorStartEvent()242 void GarbageCollectorStartEvent() 243 { 244 if (UNLIKELY(has_garbage_collector_listeners_)) { 245 for (auto *listener : garbage_collector_listeners_) { 246 if (listener != nullptr) { 247 listener->GarbageCollectorStart(); 248 } 249 } 250 } 251 } 252 GarbageCollectorFinishEvent()253 void GarbageCollectorFinishEvent() 254 { 255 if (UNLIKELY(has_garbage_collector_listeners_)) { 256 for (auto *listener : garbage_collector_listeners_) { 257 if (listener != nullptr) { 258 listener->GarbageCollectorFinish(); 259 } 260 } 261 } 262 } 263 ExceptionCatchEvent(ManagedThread * thread,Method * method,uint32_t bc_offset)264 void ExceptionCatchEvent(ManagedThread *thread, Method *method, uint32_t bc_offset) 265 { 266 if (UNLIKELY(has_exception_listeners_)) { 267 for (auto *listener : exception_listeners_) { 268 if (listener != nullptr) { 269 listener->ExceptionCatch(thread, method, bc_offset); 270 } 271 } 272 } 273 } 274 VmStartEvent()275 void VmStartEvent() 276 { 277 if (UNLIKELY(has_vm_events_listeners_)) { 278 for (auto *listener : vm_events_listeners_) { 279 if (listener != nullptr) { 280 listener->VmStart(); 281 } 282 } 283 } 284 } 285 VmInitializationEvent(ManagedThread::ThreadId thread_id)286 void VmInitializationEvent(ManagedThread::ThreadId thread_id) 287 { 288 if (UNLIKELY(has_vm_events_listeners_)) { 289 for (auto *listener : vm_events_listeners_) { 290 if (listener != nullptr) { 291 listener->VmInitialization(thread_id); 292 } 293 } 294 } 295 } 296 VmDeathEvent()297 void VmDeathEvent() 298 { 299 if (UNLIKELY(has_vm_events_listeners_)) { 300 for (auto *listener : vm_events_listeners_) { 301 if (listener != nullptr) { 302 listener->VmDeath(); 303 } 304 } 305 } 306 } 307 MethodEntryEvent(ManagedThread * thread,Method * method)308 void MethodEntryEvent(ManagedThread *thread, Method *method) 309 { 310 if (UNLIKELY(has_method_listeners_)) { 311 for (auto *listener : method_listeners_) { 312 if (listener != nullptr) { 313 listener->MethodEntry(thread, method); 314 } 315 } 316 } 317 } 318 MethodExitEvent(ManagedThread * thread,Method * method)319 void MethodExitEvent(ManagedThread *thread, Method *method) 320 { 321 if (UNLIKELY(has_method_listeners_)) { 322 for (auto *listener : method_listeners_) { 323 if (listener != nullptr) { 324 listener->MethodExit(thread, method); 325 } 326 } 327 } 328 } 329 ClassLoadEvent(Class * klass)330 void ClassLoadEvent(Class *klass) 331 { 332 if (UNLIKELY(has_class_listeners_)) { 333 for (auto *listener : class_listeners_) { 334 if (listener != nullptr) { 335 listener->ClassLoad(klass); 336 } 337 } 338 } 339 } 340 ClassPrepareEvent(Class * klass)341 void ClassPrepareEvent(Class *klass) 342 { 343 if (UNLIKELY(has_class_listeners_)) { 344 for (auto *listener : class_listeners_) { 345 if (listener != nullptr) { 346 listener->ClassPrepare(klass); 347 } 348 } 349 } 350 } 351 MonitorWaitEvent(ObjectHeader * object,int64_t timeout)352 void MonitorWaitEvent(ObjectHeader *object, int64_t timeout) 353 { 354 if (UNLIKELY(has_monitor_listeners_)) { 355 // If we need to support multiple monitor listeners, 356 // the object must be wrapped to ObjectHandle to protect from GC move 357 ASSERT(monitor_listeners_.size() == 1); 358 auto *listener = monitor_listeners_.front(); 359 if (listener != nullptr) { 360 listener->MonitorWait(object, timeout); 361 } 362 } 363 } 364 MonitorWaitedEvent(ObjectHeader * object,bool timed_out)365 void MonitorWaitedEvent(ObjectHeader *object, bool timed_out) 366 { 367 if (UNLIKELY(has_monitor_listeners_)) { 368 // If we need to support multiple monitor listeners, 369 // the object must be wrapped to ObjectHandle to protect from GC move 370 ASSERT(monitor_listeners_.size() == 1); 371 auto *listener = monitor_listeners_.front(); 372 if (listener != nullptr) { 373 monitor_listeners_.front()->MonitorWaited(object, timed_out); 374 } 375 } 376 } 377 MonitorContendedEnterEvent(ObjectHeader * object)378 void MonitorContendedEnterEvent(ObjectHeader *object) 379 { 380 if (UNLIKELY(has_monitor_listeners_)) { 381 // If we need to support multiple monitor listeners, 382 // the object must be wrapped to ObjectHandle to protect from GC move 383 ASSERT(monitor_listeners_.size() == 1); 384 auto *listener = monitor_listeners_.front(); 385 if (listener != nullptr) { 386 monitor_listeners_.front()->MonitorContendedEnter(object); 387 } 388 } 389 } 390 MonitorContendedEnteredEvent(ObjectHeader * object)391 void MonitorContendedEnteredEvent(ObjectHeader *object) 392 { 393 if (UNLIKELY(has_monitor_listeners_)) { 394 // If we need to support multiple monitor listeners, 395 // the object must be wrapped to ObjectHandle to protect from GC move 396 ASSERT(monitor_listeners_.size() == 1); 397 auto *listener = monitor_listeners_.front(); 398 if (listener != nullptr) { 399 monitor_listeners_.front()->MonitorContendedEntered(object); 400 } 401 } 402 } 403 HasAllocationListeners()404 bool HasAllocationListeners() const 405 { 406 return has_allocation_listeners_; 407 } 408 ObjectAllocEvent(BaseClass * klass,ObjectHeader * object,ManagedThread * thread,size_t size)409 void ObjectAllocEvent(BaseClass *klass, ObjectHeader *object, ManagedThread *thread, size_t size) const 410 { 411 if (UNLIKELY(has_allocation_listeners_)) { 412 // If we need to support multiple allocation listeners, 413 // the object must be wrapped to ObjectHandle to protect from GC move 414 ASSERT(allocation_listeners_.size() == 1); 415 auto *listener = allocation_listeners_.front(); 416 if (listener != nullptr) { 417 allocation_listeners_.front()->ObjectAlloc(klass, object, thread, size); 418 } 419 } 420 } 421 DdmPublishChunk(uint32_t type,const Span<const uint8_t> & data)422 void DdmPublishChunk(uint32_t type, const Span<const uint8_t> &data) 423 { 424 os::memory::ReadLockHolder holder(ddm_lock_); 425 for (auto *listener : ddm_listeners_) { 426 listener->DdmPublishChunk(type, data); 427 } 428 } 429 StartDebugger()430 void StartDebugger() 431 { 432 os::memory::ReadLockHolder holder(debugger_lock_); 433 for (auto *listener : debugger_listeners_) { 434 listener->StartDebugger(); 435 } 436 } 437 StopDebugger()438 void StopDebugger() 439 { 440 os::memory::ReadLockHolder holder(debugger_lock_); 441 for (auto *listener : debugger_listeners_) { 442 listener->StopDebugger(); 443 } 444 } 445 IsDebuggerConfigured()446 bool IsDebuggerConfigured() 447 { 448 os::memory::ReadLockHolder holder(debugger_lock_); 449 for (auto *listener : debugger_listeners_) { 450 if (!listener->IsDebuggerConfigured()) { 451 return false; 452 } 453 } 454 return true; 455 } 456 AddDdmListener(DdmListener * listener)457 void AddDdmListener(DdmListener *listener) 458 { 459 os::memory::WriteLockHolder holder(ddm_lock_); 460 ddm_listeners_.push_back(listener); 461 } 462 SetRendezvous(Rendezvous * rendezvous)463 void SetRendezvous(Rendezvous *rendezvous) 464 { 465 rendezvous_ = rendezvous; 466 } 467 RemoveDdmListener(DdmListener * listener)468 void RemoveDdmListener(DdmListener *listener) 469 { 470 os::memory::WriteLockHolder holder(ddm_lock_); 471 RemoveListener(ddm_listeners_, listener); 472 } 473 AddDebuggerListener(DebuggerListener * listener)474 void AddDebuggerListener(DebuggerListener *listener) 475 { 476 os::memory::WriteLockHolder holder(debugger_lock_); 477 debugger_listeners_.push_back(listener); 478 } 479 RemoveDebuggerListener(DebuggerListener * listener)480 void RemoveDebuggerListener(DebuggerListener *listener) 481 { 482 os::memory::WriteLockHolder holder(debugger_lock_); 483 RemoveListener(debugger_listeners_, listener); 484 } 485 486 private: AddListenerIfMatches(RuntimeListener * listener,uint32_t event_mask,PandaList<RuntimeListener * > * listener_group,Event event_modifier,bool * event_flag)487 static void AddListenerIfMatches(RuntimeListener *listener, uint32_t event_mask, 488 PandaList<RuntimeListener *> *listener_group, Event event_modifier, 489 bool *event_flag) 490 { 491 if ((event_mask & event_modifier) != 0) { 492 // If a free group item presents, use it, otherwise push back a new item 493 auto it = std::find(listener_group->begin(), listener_group->end(), nullptr); 494 if (it != listener_group->end()) { 495 *it = listener; 496 } else { 497 listener_group->push_back(listener); 498 } 499 *event_flag = true; 500 } 501 } 502 503 template <typename Container, typename T> RemoveListener(Container & c,T & listener)504 ALWAYS_INLINE void RemoveListener(Container &c, T &listener) 505 { 506 c.erase(std::remove_if(c.begin(), c.end(), [&listener](const T &elem) { return listener == elem; })); 507 } 508 RemoveListenerIfMatches(RuntimeListener * listener,uint32_t event_mask,PandaList<RuntimeListener * > * listener_group,Event event_modifier,bool * event_flag)509 static void RemoveListenerIfMatches(RuntimeListener *listener, uint32_t event_mask, 510 PandaList<RuntimeListener *> *listener_group, Event event_modifier, 511 bool *event_flag) 512 { 513 if ((event_mask & event_modifier) != 0) { 514 auto it = std::find(listener_group->begin(), listener_group->end(), listener); 515 if (it == listener_group->end()) { 516 return; 517 } 518 // Removing a listener is not safe, because the iteration can not be completed in another thread. 519 // We just set the item to null in the group 520 *it = nullptr; 521 522 // Check if any listener presents and updates the flag if not 523 if (std::find_if(listener_group->begin(), listener_group->end(), 524 [](RuntimeListener *item) { return item != nullptr; }) == listener_group->end()) { 525 *event_flag = false; 526 } 527 } 528 } 529 530 PandaList<RuntimeListener *> bytecode_pc_listeners_; 531 PandaList<RuntimeListener *> load_module_listeners_; 532 PandaList<RuntimeListener *> thread_events_listeners_; 533 PandaList<RuntimeListener *> garbage_collector_listeners_; 534 PandaList<RuntimeListener *> exception_listeners_; 535 PandaList<RuntimeListener *> vm_events_listeners_; 536 PandaList<RuntimeListener *> method_listeners_; 537 PandaList<RuntimeListener *> class_listeners_; 538 PandaList<RuntimeListener *> monitor_listeners_; 539 PandaList<RuntimeListener *> allocation_listeners_; 540 541 PandaList<DdmListener *> ddm_listeners_; 542 os::memory::RWLock ddm_lock_; 543 bool has_bytecode_pc_listeners_ = false; 544 bool has_load_module_listeners_ = false; 545 bool has_thread_events_listeners_ = false; 546 bool has_garbage_collector_listeners_ = false; 547 bool has_exception_listeners_ = false; 548 bool has_vm_events_listeners_ = false; 549 bool has_method_listeners_ = false; 550 bool has_class_listeners_ = false; 551 bool has_monitor_listeners_ = false; 552 bool has_allocation_listeners_ = false; 553 Rendezvous *rendezvous_ {nullptr}; 554 555 os::memory::RWLock debugger_lock_; 556 PandaList<DebuggerListener *> debugger_listeners_; 557 }; 558 559 } // namespace panda 560 561 #endif // PANDA_RUNTIME_INCLUDE_RUNTIME_NOTIFICATION_H_ 562