• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2024 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 #ifndef PANDA_RUNTIME_RUNTIME_NOTIFICATION_H_
16 #define PANDA_RUNTIME_RUNTIME_NOTIFICATION_H_
17 
18 #include <cstdint>
19 #include <optional>
20 #include <string_view>
21 
22 #include "libpandabase/os/mutex.h"
23 #include "runtime/include/console_call_type.h"
24 #include "runtime/include/coretypes/tagged_value.h"
25 #include "runtime/include/locks.h"
26 #include "runtime/include/mem/panda_containers.h"
27 #include "runtime/include/mem/panda_string.h"
28 #include "runtime/include/runtime.h"
29 #include "runtime/handle_scope-inl.h"
30 
31 namespace ark {
32 
33 class Method;
34 class Class;
35 class Rendezvous;
36 
37 class RuntimeListener {
38 public:
39     RuntimeListener() = default;
40     virtual ~RuntimeListener() = default;
41     DEFAULT_COPY_SEMANTIC(RuntimeListener);
42     DEFAULT_MOVE_SEMANTIC(RuntimeListener);
43 
LoadModule(std::string_view name)44     virtual void LoadModule([[maybe_unused]] std::string_view name) {}
45 
ThreadStart(ManagedThread * managedThread)46     virtual void ThreadStart([[maybe_unused]] ManagedThread *managedThread) {}
ThreadEnd(ManagedThread * managedThread)47     virtual void ThreadEnd([[maybe_unused]] ManagedThread *managedThread) {}
48 
BytecodePcChanged(ManagedThread * thread,Method * method,uint32_t bcOffset)49     virtual void BytecodePcChanged([[maybe_unused]] ManagedThread *thread, [[maybe_unused]] Method *method,
50                                    [[maybe_unused]] uint32_t bcOffset)
51     {
52     }
53 
GarbageCollectorStart()54     virtual void GarbageCollectorStart() {}
GarbageCollectorFinish()55     virtual void GarbageCollectorFinish() {}
56 
ExceptionThrow(ManagedThread * thread,Method * method,ObjectHeader * exceptionObject,uint32_t bcOffset)57     virtual void ExceptionThrow([[maybe_unused]] ManagedThread *thread, [[maybe_unused]] Method *method,
58                                 [[maybe_unused]] ObjectHeader *exceptionObject, [[maybe_unused]] uint32_t bcOffset)
59     {
60     }
61 
ExceptionCatch(ManagedThread * thread,Method * method,ObjectHeader * exceptionObject,uint32_t bcOffset)62     virtual void ExceptionCatch([[maybe_unused]] ManagedThread *thread, [[maybe_unused]] Method *method,
63                                 [[maybe_unused]] ObjectHeader *exceptionObject, [[maybe_unused]] uint32_t bcOffset)
64     {
65     }
66 
ConsoleCall(ManagedThread * thread,ConsoleCallType type,uint64_t timestamp,const PandaVector<TypedValue> & arguments)67     virtual void ConsoleCall([[maybe_unused]] ManagedThread *thread, [[maybe_unused]] ConsoleCallType type,
68                              [[maybe_unused]] uint64_t timestamp,
69                              [[maybe_unused]] const PandaVector<TypedValue> &arguments)
70     {
71     }
72 
VmStart()73     virtual void VmStart() {}
VmInitialization(ManagedThread * managedThread)74     virtual void VmInitialization([[maybe_unused]] ManagedThread *managedThread) {}
VmDeath()75     virtual void VmDeath() {}
76 
MethodEntry(ManagedThread * thread,Method * method)77     virtual void MethodEntry([[maybe_unused]] ManagedThread *thread, [[maybe_unused]] Method *method) {}
MethodExit(ManagedThread * thread,Method * method)78     virtual void MethodExit([[maybe_unused]] ManagedThread *thread, [[maybe_unused]] Method *method) {}
79 
ClassLoad(Class * klass)80     virtual void ClassLoad([[maybe_unused]] Class *klass) {}
ClassPrepare(Class * klass)81     virtual void ClassPrepare([[maybe_unused]] Class *klass) {}
82 
MonitorWait(ObjectHeader * object,int64_t timeout)83     virtual void MonitorWait([[maybe_unused]] ObjectHeader *object, [[maybe_unused]] int64_t timeout) {}
MonitorWaited(ObjectHeader * object,bool timedOut)84     virtual void MonitorWaited([[maybe_unused]] ObjectHeader *object, [[maybe_unused]] bool timedOut) {}
MonitorContendedEnter(ObjectHeader * object)85     virtual void MonitorContendedEnter([[maybe_unused]] ObjectHeader *object) {}
MonitorContendedEntered(ObjectHeader * object)86     virtual void MonitorContendedEntered([[maybe_unused]] ObjectHeader *object) {}
87 
ObjectAlloc(BaseClass * klass,ObjectHeader * object,ManagedThread * thread,size_t size)88     virtual void ObjectAlloc([[maybe_unused]] BaseClass *klass, [[maybe_unused]] ObjectHeader *object,
89                              [[maybe_unused]] ManagedThread *thread, [[maybe_unused]] size_t size)
90     {
91     }
92 
93     // Deprecated events
ThreadStart(ManagedThread::ThreadId threadId)94     virtual void ThreadStart([[maybe_unused]] ManagedThread::ThreadId threadId) {}
ThreadEnd(ManagedThread::ThreadId threadId)95     virtual void ThreadEnd([[maybe_unused]] ManagedThread::ThreadId threadId) {}
VmInitialization(ManagedThread::ThreadId threadId)96     virtual void VmInitialization([[maybe_unused]] ManagedThread::ThreadId threadId) {}
ExceptionCatch(const ManagedThread * thread,const Method * method,uint32_t bcOffset)97     virtual void ExceptionCatch([[maybe_unused]] const ManagedThread *thread, [[maybe_unused]] const Method *method,
98                                 [[maybe_unused]] uint32_t bcOffset)
99     {
100     }
101 };
102 
103 class DebuggerListener {
104 public:
105     DebuggerListener() = default;
106     virtual ~DebuggerListener() = default;
107     DEFAULT_COPY_SEMANTIC(DebuggerListener);
108     DEFAULT_MOVE_SEMANTIC(DebuggerListener);
109 
110     virtual void StartDebugger() = 0;
111     virtual void StopDebugger() = 0;
112     virtual bool IsDebuggerConfigured() = 0;
113 };
114 
115 class RuntimeNotificationManager {
116 public:
117     enum Event : uint32_t {
118         BYTECODE_PC_CHANGED = 0x01,
119         LOAD_MODULE = 0x02,
120         THREAD_EVENTS = 0x04,
121         GARBAGE_COLLECTOR_EVENTS = 0x08,
122         EXCEPTION_EVENTS = 0x10,
123         VM_EVENTS = 0x20,
124         METHOD_EVENTS = 0x40,
125         CLASS_EVENTS = 0x80,
126         MONITOR_EVENTS = 0x100,
127         ALLOCATION_EVENTS = 0x200,
128         CONSOLE_EVENTS = 0x400,
129         ALL = 0xFFFFFFFF
130     };
131 
RuntimeNotificationManager(mem::AllocatorPtr<mem::AllocatorPurpose::ALLOCATOR_PURPOSE_INTERNAL> allocator)132     explicit RuntimeNotificationManager(mem::AllocatorPtr<mem::AllocatorPurpose::ALLOCATOR_PURPOSE_INTERNAL> allocator)
133         : bytecodePcListeners_(allocator->Adapter()),
134           loadModuleListeners_(allocator->Adapter()),
135           threadEventsListeners_(allocator->Adapter()),
136           garbageCollectorListeners_(allocator->Adapter()),
137           exceptionListeners_(allocator->Adapter()),
138           vmEventsListeners_(allocator->Adapter()),
139           methodListeners_(allocator->Adapter()),
140           classListeners_(allocator->Adapter()),
141           monitorListeners_(allocator->Adapter())
142     {
143     }
144 
AddListener(RuntimeListener * listener,uint32_t eventMask)145     void AddListener(RuntimeListener *listener, uint32_t eventMask)
146     {
147         ScopedSuspendAllThreads ssat(rendezvous_);
148         AddListenerIfMatches(listener, eventMask, &bytecodePcListeners_, Event::BYTECODE_PC_CHANGED,
149                              &hasBytecodePcListeners_);
150 
151         AddListenerIfMatches(listener, eventMask, &loadModuleListeners_, Event::LOAD_MODULE, &hasLoadModuleListeners_);
152 
153         AddListenerIfMatches(listener, eventMask, &threadEventsListeners_, Event::THREAD_EVENTS,
154                              &hasThreadEventsListeners_);
155 
156         AddListenerIfMatches(listener, eventMask, &exceptionListeners_, Event::EXCEPTION_EVENTS,
157                              &hasExceptionListeners_);
158 
159         AddListenerIfMatches(listener, eventMask, &vmEventsListeners_, Event::VM_EVENTS, &hasVmEventsListeners_);
160 
161         AddListenerIfMatches(listener, eventMask, &methodListeners_, Event::METHOD_EVENTS, &hasMethodListeners_);
162 
163         AddListenerIfMatches(listener, eventMask, &classListeners_, Event::CLASS_EVENTS, &hasClassListeners_);
164 
165         AddListenerIfMatches(listener, eventMask, &monitorListeners_, Event::MONITOR_EVENTS, &hasMonitorListeners_);
166 
167         AddListenerIfMatches(listener, eventMask, &allocationListeners_, Event::ALLOCATION_EVENTS,
168                              &hasAllocationListeners_);
169 
170         AddListenerIfMatches(listener, eventMask, &consoleListeners_, Event::CONSOLE_EVENTS, &hasConsoleListeners_);
171 
172         {
173             // We cannot stop GC thread, so holding lock to avoid data race
174             os::memory::WriteLockHolder rwlock(gcEventLock_);
175             AddListenerIfMatches(listener, eventMask, &garbageCollectorListeners_, Event::GARBAGE_COLLECTOR_EVENTS,
176                                  &hasGarbageCollectorListeners_);
177         }
178     }
179 
RemoveListener(RuntimeListener * listener,uint32_t eventMask)180     void RemoveListener(RuntimeListener *listener, uint32_t eventMask)
181     {
182         ScopedSuspendAllThreads ssat(rendezvous_);
183         RemoveListenerIfMatches(listener, eventMask, &bytecodePcListeners_, Event::BYTECODE_PC_CHANGED,
184                                 &hasBytecodePcListeners_);
185 
186         RemoveListenerIfMatches(listener, eventMask, &loadModuleListeners_, Event::LOAD_MODULE,
187                                 &hasLoadModuleListeners_);
188 
189         RemoveListenerIfMatches(listener, eventMask, &threadEventsListeners_, Event::THREAD_EVENTS,
190                                 &hasThreadEventsListeners_);
191 
192         RemoveListenerIfMatches(listener, eventMask, &exceptionListeners_, Event::EXCEPTION_EVENTS,
193                                 &hasExceptionListeners_);
194 
195         RemoveListenerIfMatches(listener, eventMask, &vmEventsListeners_, Event::VM_EVENTS, &hasVmEventsListeners_);
196 
197         RemoveListenerIfMatches(listener, eventMask, &methodListeners_, Event::METHOD_EVENTS, &hasMethodListeners_);
198 
199         RemoveListenerIfMatches(listener, eventMask, &classListeners_, Event::CLASS_EVENTS, &hasClassListeners_);
200 
201         RemoveListenerIfMatches(listener, eventMask, &monitorListeners_, Event::MONITOR_EVENTS, &hasMonitorListeners_);
202 
203         RemoveListenerIfMatches(listener, eventMask, &allocationListeners_, Event::ALLOCATION_EVENTS,
204                                 &hasAllocationListeners_);
205 
206         RemoveListenerIfMatches(listener, eventMask, &consoleListeners_, Event::CONSOLE_EVENTS, &hasConsoleListeners_);
207 
208         {
209             // We cannot stop GC thread, so holding lock to avoid data race
210             os::memory::WriteLockHolder rwlock(gcEventLock_);
211             RemoveListenerIfMatches(listener, eventMask, &garbageCollectorListeners_, Event::GARBAGE_COLLECTOR_EVENTS,
212                                     &hasGarbageCollectorListeners_);
213         }
214     }
215 
LoadModuleEvent(std::string_view name)216     void LoadModuleEvent(std::string_view name)
217     {
218         if (UNLIKELY(hasLoadModuleListeners_)) {
219             for (auto *listener : loadModuleListeners_) {
220                 if (listener != nullptr) {
221                     listener->LoadModule(name);
222                 }
223             }
224         }
225     }
226 
ThreadStartEvent(ManagedThread * managedThread)227     void ThreadStartEvent(ManagedThread *managedThread)
228     {
229         if (UNLIKELY(hasThreadEventsListeners_)) {
230             for (auto *listener : threadEventsListeners_) {
231                 if (listener != nullptr) {
232                     listener->ThreadStart(managedThread);
233                 }
234             }
235         }
236     }
237 
ThreadEndEvent(ManagedThread * managedThread)238     void ThreadEndEvent(ManagedThread *managedThread)
239     {
240         if (UNLIKELY(hasThreadEventsListeners_)) {
241             for (auto *listener : threadEventsListeners_) {
242                 if (listener != nullptr) {
243                     listener->ThreadEnd(managedThread);
244                 }
245             }
246         }
247     }
248 
BytecodePcChangedEvent(ManagedThread * thread,Method * method,uint32_t bcOffset)249     void BytecodePcChangedEvent(ManagedThread *thread, Method *method, uint32_t bcOffset)
250     {
251         if (UNLIKELY(hasBytecodePcListeners_)) {
252             for (auto *listener : bytecodePcListeners_) {
253                 if (listener != nullptr) {
254                     listener->BytecodePcChanged(thread, method, bcOffset);
255                 }
256             }
257         }
258     }
259 
GarbageCollectorStartEvent()260     void GarbageCollectorStartEvent()
261     {
262         if (UNLIKELY(hasGarbageCollectorListeners_)) {
263             os::memory::ReadLockHolder rwlock(gcEventLock_);
264             for (auto *listener : garbageCollectorListeners_) {
265                 if (listener != nullptr) {
266                     listener->GarbageCollectorStart();
267                 }
268             }
269         }
270     }
271 
GarbageCollectorFinishEvent()272     void GarbageCollectorFinishEvent()
273     {
274         if (UNLIKELY(hasGarbageCollectorListeners_)) {
275             os::memory::ReadLockHolder rwlock(gcEventLock_);
276             for (auto *listener : garbageCollectorListeners_) {
277                 if (listener != nullptr) {
278                     listener->GarbageCollectorFinish();
279                 }
280             }
281         }
282     }
283 
ExceptionThrowEvent(ManagedThread * thread,Method * method,ObjectHeader * exceptionObject,uint32_t bcOffset)284     void ExceptionThrowEvent(ManagedThread *thread, Method *method, ObjectHeader *exceptionObject, uint32_t bcOffset)
285     {
286         if (UNLIKELY(hasExceptionListeners_)) {
287             [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread);
288             VMHandle<ObjectHeader> objHandle(thread, exceptionObject);
289             for (auto *listener : exceptionListeners_) {
290                 if (listener != nullptr) {
291                     listener->ExceptionThrow(thread, method, objHandle.GetPtr(), bcOffset);
292                 }
293             }
294         }
295     }
296 
ExceptionCatchEvent(ManagedThread * thread,Method * method,ObjectHeader * exceptionObject,uint32_t bcOffset)297     void ExceptionCatchEvent(ManagedThread *thread, Method *method, ObjectHeader *exceptionObject, uint32_t bcOffset)
298     {
299         if (UNLIKELY(hasExceptionListeners_)) {
300             [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread);
301             VMHandle<ObjectHeader> objHandle(thread, exceptionObject);
302             for (auto *listener : exceptionListeners_) {
303                 if (listener != nullptr) {
304                     listener->ExceptionCatch(thread, method, objHandle.GetPtr(), bcOffset);
305                 }
306             }
307         }
308     }
309 
VmStartEvent()310     void VmStartEvent()
311     {
312         if (UNLIKELY(hasVmEventsListeners_)) {
313             for (auto *listener : vmEventsListeners_) {
314                 if (listener != nullptr) {
315                     listener->VmStart();
316                 }
317             }
318         }
319     }
320 
VmInitializationEvent(ManagedThread * managedThread)321     void VmInitializationEvent(ManagedThread *managedThread)
322     {
323         if (UNLIKELY(hasVmEventsListeners_)) {
324             for (auto *listener : vmEventsListeners_) {
325                 if (listener != nullptr) {
326                     listener->VmInitialization(managedThread);
327                 }
328             }
329         }
330     }
331 
332     // Deprecated API
VmInitializationEvent(ManagedThread::ThreadId threadId)333     void VmInitializationEvent(ManagedThread::ThreadId threadId)
334     {
335         if (UNLIKELY(hasVmEventsListeners_)) {
336             for (auto *listener : vmEventsListeners_) {
337                 if (listener != nullptr) {
338                     listener->VmInitialization(threadId);
339                 }
340             }
341         }
342     }
343 
VmDeathEvent()344     void VmDeathEvent()
345     {
346         if (UNLIKELY(hasVmEventsListeners_)) {
347             for (auto *listener : vmEventsListeners_) {
348                 if (listener != nullptr) {
349                     listener->VmDeath();
350                 }
351             }
352         }
353     }
354 
MethodEntryEvent(ManagedThread * thread,Method * method)355     void MethodEntryEvent(ManagedThread *thread, Method *method)
356     {
357         if (UNLIKELY(hasMethodListeners_)) {
358             for (auto *listener : methodListeners_) {
359                 if (listener != nullptr) {
360                     listener->MethodEntry(thread, method);
361                 }
362             }
363         }
364     }
365 
MethodExitEvent(ManagedThread * thread,Method * method)366     void MethodExitEvent(ManagedThread *thread, Method *method)
367     {
368         if (UNLIKELY(hasMethodListeners_)) {
369             for (auto *listener : methodListeners_) {
370                 if (listener != nullptr) {
371                     listener->MethodExit(thread, method);
372                 }
373             }
374         }
375     }
376 
ClassLoadEvent(Class * klass)377     void ClassLoadEvent(Class *klass)
378     {
379         if (UNLIKELY(hasClassListeners_)) {
380             for (auto *listener : classListeners_) {
381                 if (listener != nullptr) {
382                     listener->ClassLoad(klass);
383                 }
384             }
385         }
386     }
387 
ClassPrepareEvent(Class * klass)388     void ClassPrepareEvent(Class *klass)
389     {
390         if (UNLIKELY(hasClassListeners_)) {
391             for (auto *listener : classListeners_) {
392                 if (listener != nullptr) {
393                     listener->ClassPrepare(klass);
394                 }
395             }
396         }
397     }
398 
MonitorWaitEvent(ObjectHeader * object,int64_t timeout)399     void MonitorWaitEvent(ObjectHeader *object, int64_t timeout)
400     {
401         if (UNLIKELY(hasMonitorListeners_)) {
402             // If we need to support multiple monitor listeners,
403             // the object must be wrapped to ObjectHandle to protect from GC move
404             ASSERT(monitorListeners_.size() == 1);
405             auto *listener = monitorListeners_.front();
406             if (listener != nullptr) {
407                 listener->MonitorWait(object, timeout);
408             }
409         }
410     }
411 
MonitorWaitedEvent(ObjectHeader * object,bool timedOut)412     void MonitorWaitedEvent(ObjectHeader *object, bool timedOut)
413     {
414         if (UNLIKELY(hasMonitorListeners_)) {
415             // If we need to support multiple monitor listeners,
416             // the object must be wrapped to ObjectHandle to protect from GC move
417             ASSERT(monitorListeners_.size() == 1);
418             auto *listener = monitorListeners_.front();
419             if (listener != nullptr) {
420                 monitorListeners_.front()->MonitorWaited(object, timedOut);
421             }
422         }
423     }
424 
MonitorContendedEnterEvent(ObjectHeader * object)425     void MonitorContendedEnterEvent(ObjectHeader *object)
426     {
427         if (UNLIKELY(hasMonitorListeners_)) {
428             // If we need to support multiple monitor listeners,
429             // the object must be wrapped to ObjectHandle to protect from GC move
430             ASSERT(monitorListeners_.size() == 1);
431             auto *listener = monitorListeners_.front();
432             if (listener != nullptr) {
433                 monitorListeners_.front()->MonitorContendedEnter(object);
434             }
435         }
436     }
437 
MonitorContendedEnteredEvent(ObjectHeader * object)438     void MonitorContendedEnteredEvent(ObjectHeader *object)
439     {
440         if (UNLIKELY(hasMonitorListeners_)) {
441             // If we need to support multiple monitor listeners,
442             // the object must be wrapped to ObjectHandle to protect from GC move
443             ASSERT(monitorListeners_.size() == 1);
444             auto *listener = monitorListeners_.front();
445             if (listener != nullptr) {
446                 monitorListeners_.front()->MonitorContendedEntered(object);
447             }
448         }
449     }
450 
HasAllocationListeners()451     bool HasAllocationListeners() const
452     {
453         return hasAllocationListeners_;
454     }
455 
ObjectAllocEvent(BaseClass * klass,ObjectHeader * object,ManagedThread * thread,size_t size)456     void ObjectAllocEvent(BaseClass *klass, ObjectHeader *object, ManagedThread *thread, size_t size) const
457     {
458         if (UNLIKELY(hasAllocationListeners_)) {
459             // If we need to support multiple allocation listeners,
460             // the object must be wrapped to ObjectHandle to protect from GC move
461             ASSERT(allocationListeners_.size() == 1);
462             auto *listener = allocationListeners_.front();
463             if (listener != nullptr) {
464                 allocationListeners_.front()->ObjectAlloc(klass, object, thread, size);
465             }
466         }
467     }
468 
ConsoleCallEvent(ManagedThread * thread,ConsoleCallType type,uint64_t timestamp,const PandaVector<TypedValue> & arguments)469     void ConsoleCallEvent(ManagedThread *thread, ConsoleCallType type, uint64_t timestamp,
470                           const PandaVector<TypedValue> &arguments) const
471     {
472         if (UNLIKELY(hasConsoleListeners_)) {
473             for (auto listener : consoleListeners_) {
474                 if (listener != nullptr) {
475                     listener->ConsoleCall(thread, type, timestamp, arguments);
476                 }
477             }
478         }
479     }
480 
StartDebugger()481     void StartDebugger()
482     {
483         os::memory::ReadLockHolder holder(debuggerLock_);
484         for (auto *listener : debuggerListeners_) {
485             listener->StartDebugger();
486         }
487     }
488 
StopDebugger()489     void StopDebugger()
490     {
491         os::memory::ReadLockHolder holder(debuggerLock_);
492         for (auto *listener : debuggerListeners_) {
493             listener->StopDebugger();
494         }
495     }
496 
IsDebuggerConfigured()497     bool IsDebuggerConfigured()
498     {
499         os::memory::ReadLockHolder holder(debuggerLock_);
500         for (auto *listener : debuggerListeners_) {
501             if (!listener->IsDebuggerConfigured()) {
502                 return false;
503             }
504         }
505         return true;
506     }
507 
SetRendezvous(Rendezvous * rendezvous)508     void SetRendezvous(Rendezvous *rendezvous)
509     {
510         rendezvous_ = rendezvous;
511     }
512 
AddDebuggerListener(DebuggerListener * listener)513     void AddDebuggerListener(DebuggerListener *listener)
514     {
515         os::memory::WriteLockHolder holder(debuggerLock_);
516         debuggerListeners_.push_back(listener);
517     }
518 
RemoveDebuggerListener(DebuggerListener * listener)519     void RemoveDebuggerListener(DebuggerListener *listener)
520     {
521         os::memory::WriteLockHolder holder(debuggerLock_);
522         RemoveListener(debuggerListeners_, listener);
523     }
524 
525 private:
526     template <typename FlagType>
AddListenerIfMatches(RuntimeListener * listener,uint32_t eventMask,PandaList<RuntimeListener * > * listenerGroup,Event eventModifier,FlagType * eventFlag)527     static void AddListenerIfMatches(RuntimeListener *listener, uint32_t eventMask,
528                                      PandaList<RuntimeListener *> *listenerGroup, Event eventModifier,
529                                      FlagType *eventFlag)
530     {
531         if ((eventMask & eventModifier) != 0) {
532             // If a free group item presents, use it, otherwise push back a new item
533             auto it = std::find(listenerGroup->begin(), listenerGroup->end(), nullptr);
534             if (it != listenerGroup->end()) {
535                 *it = listener;
536             } else {
537                 listenerGroup->push_back(listener);
538             }
539             *eventFlag = true;
540         }
541     }
542 
543     template <typename Container, typename T>
RemoveListener(Container & c,T & listener)544     ALWAYS_INLINE void RemoveListener(Container &c, T &listener)
545     {
546         c.erase(std::remove_if(c.begin(), c.end(), [&listener](const T &elem) { return listener == elem; }));
547     }
548 
549     template <typename FlagType>
RemoveListenerIfMatches(RuntimeListener * listener,uint32_t eventMask,PandaList<RuntimeListener * > * listenerGroup,Event eventModifier,FlagType * eventFlag)550     static void RemoveListenerIfMatches(RuntimeListener *listener, uint32_t eventMask,
551                                         PandaList<RuntimeListener *> *listenerGroup, Event eventModifier,
552                                         FlagType *eventFlag)
553     {
554         if ((eventMask & eventModifier) != 0) {
555             auto it = std::find(listenerGroup->begin(), listenerGroup->end(), listener);
556             if (it == listenerGroup->end()) {
557                 return;
558             }
559             // Removing a listener is not safe, because the iteration can not be completed in another thread.
560             // We just null the item in the group
561             *it = nullptr;
562 
563             // Check if any listener presents and update the flag if not
564             if (std::find_if(listenerGroup->begin(), listenerGroup->end(),
565                              [](RuntimeListener *item) { return item != nullptr; }) == listenerGroup->end()) {
566                 *eventFlag = false;
567             }
568         }
569     }
570 
571     PandaList<RuntimeListener *> bytecodePcListeners_;
572     PandaList<RuntimeListener *> loadModuleListeners_;
573     PandaList<RuntimeListener *> threadEventsListeners_;
574     PandaList<RuntimeListener *> garbageCollectorListeners_;
575     PandaList<RuntimeListener *> exceptionListeners_;
576     PandaList<RuntimeListener *> vmEventsListeners_;
577     PandaList<RuntimeListener *> methodListeners_;
578     PandaList<RuntimeListener *> classListeners_;
579     PandaList<RuntimeListener *> monitorListeners_;
580     PandaList<RuntimeListener *> allocationListeners_;
581     PandaList<RuntimeListener *> consoleListeners_;
582 
583     bool hasBytecodePcListeners_ = false;
584     bool hasLoadModuleListeners_ = false;
585     bool hasThreadEventsListeners_ = false;
586     std::atomic<bool> hasGarbageCollectorListeners_ = false;
587     bool hasExceptionListeners_ = false;
588     bool hasVmEventsListeners_ = false;
589     bool hasMethodListeners_ = false;
590     bool hasClassListeners_ = false;
591     bool hasMonitorListeners_ = false;
592     bool hasAllocationListeners_ = false;
593     bool hasConsoleListeners_ = false;
594     Rendezvous *rendezvous_ {nullptr};
595 
596     os::memory::RWLock debuggerLock_;
597     os::memory::RWLock gcEventLock_;
598     PandaList<DebuggerListener *> debuggerListeners_;
599 };
600 
601 }  // namespace ark
602 
603 #endif  // PANDA_RUNTIME_RUNTIME_NOTIFICATION_H_
604