1 /**
2 * Copyright (c) 2022-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 #include "thread_state.h"
17
18 namespace ark::tooling::inspector {
GetBreakpointsByLocation(const PtLocation & location) const19 std::vector<BreakpointId> ThreadState::GetBreakpointsByLocation(const PtLocation &location) const
20 {
21 std::vector<BreakpointId> hitBreakpoints;
22
23 auto range = breakpointLocations_.equal_range(location);
24 std::transform(range.first, range.second, std::back_inserter(hitBreakpoints), [](auto &p) { return p.second; });
25
26 return hitBreakpoints;
27 }
28
Reset()29 void ThreadState::Reset()
30 {
31 if (stepKind_ != StepKind::BREAK_ON_START) {
32 stepKind_ = StepKind::NONE;
33 }
34 stepLocations_.clear();
35 methodEntered_ = false;
36 breakpointsActive_ = true;
37 nextBreakpointId_ = 0;
38 breakpointLocations_.clear();
39 pauseOnExceptionsState_ = PauseOnExceptionsState::NONE;
40 }
41
BreakOnStart()42 void ThreadState::BreakOnStart()
43 {
44 if (!paused_) {
45 stepKind_ = StepKind::BREAK_ON_START;
46 }
47 }
48
Continue()49 void ThreadState::Continue()
50 {
51 stepKind_ = StepKind::NONE;
52 paused_ = false;
53 }
54
ContinueTo(std::unordered_set<PtLocation,HashLocation> locations)55 void ThreadState::ContinueTo(std::unordered_set<PtLocation, HashLocation> locations)
56 {
57 stepKind_ = StepKind::CONTINUE_TO;
58 stepLocations_ = std::move(locations);
59 paused_ = false;
60 }
61
StepInto(std::unordered_set<PtLocation,HashLocation> locations)62 void ThreadState::StepInto(std::unordered_set<PtLocation, HashLocation> locations)
63 {
64 stepKind_ = StepKind::STEP_INTO;
65 methodEntered_ = false;
66 stepLocations_ = std::move(locations);
67 paused_ = false;
68 }
69
StepOver(std::unordered_set<PtLocation,HashLocation> locations)70 void ThreadState::StepOver(std::unordered_set<PtLocation, HashLocation> locations)
71 {
72 stepKind_ = StepKind::STEP_OVER;
73 methodEntered_ = false;
74 stepLocations_ = std::move(locations);
75 paused_ = false;
76 }
77
StepOut()78 void ThreadState::StepOut()
79 {
80 stepKind_ = StepKind::STEP_OUT;
81 methodEntered_ = true;
82 paused_ = false;
83 }
84
Pause()85 void ThreadState::Pause()
86 {
87 if (!paused_) {
88 stepKind_ = StepKind::PAUSE;
89 }
90 }
91
SetBreakpointsActive(bool active)92 void ThreadState::SetBreakpointsActive(bool active)
93 {
94 breakpointsActive_ = active;
95 }
96
SetBreakpoint(const std::vector<PtLocation> & locations)97 BreakpointId ThreadState::SetBreakpoint(const std::vector<PtLocation> &locations)
98 {
99 auto id = nextBreakpointId_++;
100 for (auto &location : locations) {
101 breakpointLocations_.emplace(location, id);
102 }
103
104 return id;
105 }
106
RemoveBreakpoint(BreakpointId id)107 void ThreadState::RemoveBreakpoint(BreakpointId id)
108 {
109 for (auto it = breakpointLocations_.begin(); it != breakpointLocations_.end();) {
110 if (it->second == id) {
111 it = breakpointLocations_.erase(it);
112 } else {
113 ++it;
114 }
115 }
116 }
117
SetPauseOnExceptions(PauseOnExceptionsState state)118 void ThreadState::SetPauseOnExceptions(PauseOnExceptionsState state)
119 {
120 pauseOnExceptionsState_ = state;
121 }
122
OnException(bool uncaught)123 void ThreadState::OnException(bool uncaught)
124 {
125 ASSERT(!paused_);
126 switch (pauseOnExceptionsState_) {
127 case PauseOnExceptionsState::NONE:
128 break;
129 case PauseOnExceptionsState::CAUGHT:
130 paused_ = !uncaught;
131 break;
132 case PauseOnExceptionsState::UNCAUGHT:
133 paused_ = uncaught;
134 break;
135 case PauseOnExceptionsState::ALL:
136 paused_ = true;
137 break;
138 }
139 }
140
OnFramePop()141 void ThreadState::OnFramePop()
142 {
143 ASSERT(!paused_);
144 switch (stepKind_) {
145 case StepKind::NONE:
146 case StepKind::BREAK_ON_START:
147 case StepKind::CONTINUE_TO:
148 case StepKind::PAUSE:
149 case StepKind::STEP_INTO: {
150 break;
151 }
152
153 case StepKind::STEP_OUT:
154 case StepKind::STEP_OVER: {
155 methodEntered_ = false;
156 break;
157 }
158 }
159 }
160
OnMethodEntry()161 bool ThreadState::OnMethodEntry()
162 {
163 ASSERT(!paused_);
164 switch (stepKind_) {
165 case StepKind::NONE:
166 case StepKind::BREAK_ON_START:
167 case StepKind::CONTINUE_TO:
168 case StepKind::PAUSE:
169 case StepKind::STEP_INTO: {
170 return false;
171 }
172
173 case StepKind::STEP_OUT:
174 case StepKind::STEP_OVER: {
175 return !std::exchange(methodEntered_, true);
176 }
177 }
178
179 UNREACHABLE();
180 }
181
OnSingleStep(const PtLocation & location)182 void ThreadState::OnSingleStep(const PtLocation &location)
183 {
184 ASSERT(!paused_);
185 if (!breakpointsActive_ || breakpointLocations_.find(location) == breakpointLocations_.end()) {
186 switch (stepKind_) {
187 case StepKind::NONE: {
188 paused_ = false;
189 break;
190 }
191
192 case StepKind::BREAK_ON_START: {
193 paused_ = true;
194 break;
195 }
196
197 case StepKind::CONTINUE_TO: {
198 paused_ = stepLocations_.find(location) != stepLocations_.end();
199 break;
200 }
201
202 case StepKind::PAUSE: {
203 paused_ = true;
204 break;
205 }
206
207 case StepKind::STEP_INTO: {
208 paused_ = stepLocations_.find(location) == stepLocations_.end();
209 break;
210 }
211
212 case StepKind::STEP_OUT: {
213 paused_ = !methodEntered_;
214 break;
215 }
216
217 case StepKind::STEP_OVER: {
218 paused_ = !methodEntered_ && stepLocations_.find(location) == stepLocations_.end();
219 break;
220 }
221 }
222 } else {
223 paused_ = true;
224 }
225 }
226 } // namespace ark::tooling::inspector
227