• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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_TOOLING_BACKEND_JS_DEBUGGER_H
17 #define ECMASCRIPT_TOOLING_BACKEND_JS_DEBUGGER_H
18 
19 #include "ecmascript/ecma_vm.h"
20 #include "ecmascript/js_method.h"
21 #include "ecmascript/tooling/backend/debugger_api.h"
22 #include "ecmascript/tooling/interface/notification_manager.h"
23 #include "ecmascript/tooling/interface/js_debugger_manager.h"
24 
25 namespace panda::ecmascript::tooling {
26 class JSBreakpoint {
27 public:
28     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
JSBreakpoint(JSMethod * method,uint32_t bcOffset,const Global<FunctionRef> & condFuncRef)29     JSBreakpoint(JSMethod *method, uint32_t bcOffset, const Global<FunctionRef> &condFuncRef)
30         : method_(method), bcOffset_(bcOffset), condFuncRef_(condFuncRef) {}
31     ~JSBreakpoint() = default;
32 
GetMethod()33     JSMethod *GetMethod() const
34     {
35         return method_;
36     }
37 
GetBytecodeOffset()38     uint32_t GetBytecodeOffset() const
39     {
40         return bcOffset_;
41     }
42 
43     bool operator==(const JSBreakpoint &bpoint) const
44     {
45         return GetMethod() == bpoint.GetMethod() && GetBytecodeOffset() == bpoint.GetBytecodeOffset();
46     }
47 
GetConditionFunction()48     const Global<FunctionRef> &GetConditionFunction()
49     {
50         return condFuncRef_;
51     }
52 
53     DEFAULT_COPY_SEMANTIC(JSBreakpoint);
54     DEFAULT_MOVE_SEMANTIC(JSBreakpoint);
55 
56 private:
57     JSMethod *method_;
58     uint32_t bcOffset_;
59     Global<FunctionRef> condFuncRef_;
60 };
61 
62 class HashJSBreakpoint {
63 public:
operator()64     size_t operator()(const JSBreakpoint &bpoint) const
65     {
66         return (std::hash<JSMethod *>()(bpoint.GetMethod())) ^ (std::hash<uint32_t>()(bpoint.GetBytecodeOffset()));
67     }
68 };
69 
70 class JSDebugger : public JSDebugInterface, RuntimeListener {
71 public:
JSDebugger(const EcmaVM * vm)72     explicit JSDebugger(const EcmaVM *vm) : ecmaVm_(vm)
73     {
74         notificationMgr_ = ecmaVm_->GetJsDebuggerManager()->GetNotificationManager();
75         notificationMgr_->AddListener(this);
76     }
~JSDebugger()77     ~JSDebugger() override
78     {
79         notificationMgr_->RemoveListener();
80     }
81 
RegisterHooks(PtHooks * hooks)82     void RegisterHooks(PtHooks *hooks) override
83     {
84         hooks_ = hooks;
85         // send vm start event after add hooks
86         notificationMgr_->VmStartEvent();
87     }
UnregisterHooks()88     void UnregisterHooks() override
89     {
90         // send vm death event before delete hooks
91         notificationMgr_->VmDeathEvent();
92         hooks_ = nullptr;
93     }
94 
95     bool SetBreakpoint(const JSPtLocation &location, Local<FunctionRef> condFuncRef) override;
96     bool RemoveBreakpoint(const JSPtLocation &location) override;
97     void BytecodePcChanged(JSThread *thread, JSMethod *method, uint32_t bcOffset) override;
LoadModule(std::string_view filename)98     void LoadModule(std::string_view filename) override
99     {
100         if (hooks_ == nullptr) {
101             return;
102         }
103         hooks_->LoadModule(filename);
104     }
VmStart()105     void VmStart() override
106     {
107         if (hooks_ == nullptr) {
108             return;
109         }
110         hooks_->VmStart();
111     }
VmDeath()112     void VmDeath() override
113     {
114         if (hooks_ == nullptr) {
115             return;
116         }
117         hooks_->VmDeath();
118     }
PendingJobEntry()119     void PendingJobEntry() override
120     {
121         if (hooks_ == nullptr) {
122             return;
123         }
124         hooks_->PendingJobEntry();
125     }
126 
127 private:
128     JSMethod *FindMethod(const JSPtLocation &location) const;
129     std::optional<JSBreakpoint> FindBreakpoint(const JSMethod *method, uint32_t bcOffset) const;
130     bool RemoveBreakpoint(const JSMethod *method, uint32_t bcOffset);
131     void HandleExceptionThrowEvent(const JSThread *thread, const JSMethod *method, uint32_t bcOffset);
132     bool HandleStep(const JSMethod *method, uint32_t bcOffset);
133     bool HandleBreakpoint(const JSMethod *method, uint32_t bcOffset);
134 
135     const EcmaVM *ecmaVm_;
136     PtHooks *hooks_ {nullptr};
137     NotificationManager *notificationMgr_ {nullptr};
138 
139     CUnorderedSet<JSBreakpoint, HashJSBreakpoint> breakpoints_ {};
140 };
141 }  // namespace panda::ecmascript::tooling
142 
143 #endif  // ECMASCRIPT_TOOLING_BACKEND_JS_DEBUGGER_H
144