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
16#ifndef ECMASCRIPT_DEBUGGER_NOTIFICATION_MANAGER_H
17#define ECMASCRIPT_DEBUGGER_NOTIFICATION_MANAGER_H
18
19#include <string_view>
20
21#include "ecmascript/js_handle.h"
22#include "ecmascript/js_thread.h"
23#include "ecmascript/method.h"
24
25namespace panda::ecmascript::tooling {
26class RuntimeListener {
27public:
28    RuntimeListener() = default;
29    virtual ~RuntimeListener() = default;
30    DEFAULT_COPY_SEMANTIC(RuntimeListener);
31    DEFAULT_MOVE_SEMANTIC(RuntimeListener);
32
33    virtual void LoadModule(std::string_view name, std::string_view) = 0;
34
35    virtual void BytecodePcChanged(JSThread *thread, JSHandle<Method> method,
36                                   uint32_t bcOffset) = 0;
37
38    virtual bool HandleDebuggerStmt(JSHandle<Method> method, uint32_t bcOffset) = 0;
39    virtual void VmStart() = 0;
40    virtual void VmDeath() = 0;
41    virtual void NativeCalling(const void *nativeAddress) = 0;
42    virtual void NativeReturn(const void *nativeAddress) = 0;
43    virtual void MethodEntry(JSHandle<Method> method, JSHandle<JSTaggedValue> envHandle) = 0;
44    virtual void MethodExit(JSHandle<Method> method) = 0;
45};
46
47class NotificationManager {
48public:
49    NotificationManager() = default;
50    ~NotificationManager() = default;
51    NO_COPY_SEMANTIC(NotificationManager);
52    NO_MOVE_SEMANTIC(NotificationManager);
53
54    void AddListener(RuntimeListener *listener)
55    {
56        if (listener != nullptr) {
57            listeners_.emplace_back(listener);
58        }
59    }
60    void RemoveListener(RuntimeListener *listener)
61    {
62        for (auto it = listeners_.begin(); it != listeners_.end(); ++it) {
63            if (*it == listener) {
64                listeners_.erase(it);
65                return;
66            }
67        }
68    }
69
70    void LoadModuleEvent(std::string_view name, std::string_view entryPoint) const
71    {
72        for (auto it: listeners_) {
73            it->LoadModule(name, entryPoint);
74        }
75    }
76
77    void BytecodePcChangedEvent(JSThread *thread, Method *method, uint32_t bcOffset) const
78    {
79        [[maybe_unused]] EcmaHandleScope handleScope(thread);
80        JSHandle<Method> methodHandle(thread, method);
81        for (auto it: listeners_) {
82            it->BytecodePcChanged(thread, methodHandle, bcOffset);
83        }
84    }
85
86    void DebuggerStmtEvent(JSThread *thread, Method *method, uint32_t bcOffset) const
87    {
88        JSHandle<Method> methodHandle(thread, method);
89        for (auto it: listeners_) {
90            it->HandleDebuggerStmt(methodHandle, bcOffset);
91        }
92    }
93
94    void NativeCallingEvent(const void *nativeAddress) const
95    {
96        for (auto it: listeners_) {
97            it->NativeCalling(nativeAddress);
98        }
99    }
100
101    void NativeReturnEvent(const void *nativeAddress) const
102    {
103        for (auto it: listeners_) {
104            it->NativeReturn(nativeAddress);
105        }
106    }
107
108    void VmStartEvent() const
109    {
110        for (auto it: listeners_) {
111            it->VmStart();
112        }
113    }
114    void VmDeathEvent() const
115    {
116        for (auto it: listeners_) {
117            it->VmDeath();
118        }
119    }
120
121    void MethodEntryEvent(JSThread *thread, Method *method, JSTaggedValue env) const
122    {
123        JSHandle<Method> methodHandle(thread, method);
124        JSHandle<JSTaggedValue> envHandle(thread, env);
125        for (auto it: listeners_) {
126            it->MethodEntry(methodHandle, envHandle);
127        }
128    }
129    void MethodExitEvent(JSThread *thread, Method *method) const
130    {
131        JSHandle<Method> methodHandle(thread, method);
132        for (auto it: listeners_) {
133            it->MethodExit(methodHandle);
134        }
135    }
136private:
137    std::vector<RuntimeListener*> listeners_;
138};
139}  // panda::ecmascript::tooling
140
141#endif  // ECMASCRIPT_DEBUGGER_NOTIFICATION_MANAGER_H