1 /*
2 * Copyright (c) 2023 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_TEST_UTILS_TESTCASES_JS_DROP_FRAME_TEST_H
17 #define ECMASCRIPT_TOOLING_TEST_UTILS_TESTCASES_JS_DROP_FRAME_TEST_H
18
19 #include "test/utils/test_util.h"
20
21 namespace panda::ecmascript::tooling::test {
22 class JsDropFrameTest : public TestEvents {
23 public:
JsDropFrameTest()24 JsDropFrameTest()
25 {
26 channel_ = new JsDropFrameTestChannel();
27
28 breakpoint = [this](const JSPtLocation &location) {
29 ASSERT_TRUE(location.GetMethodId().IsValid());
30 ++breakpointCounter_;
31 debugger_->NotifyPaused(location, PauseReason::INSTRUMENTATION);
32 static_cast<JsDropFrameTestChannel *>(channel_)->IncreaseCheckVariableCounter();
33 DropFrameIfChecked();
34 TestUtil::SuspendUntilContinue(DebugEvent::BREAKPOINT, location);
35 return true;
36 };
37
38 singleStep = [this](const JSPtLocation &location) {
39 if (debugger_->NotifySingleStep(location)) {
40 debugger_->NotifyPaused({}, PauseReason::INSTRUMENTATION);
41 static_cast<JsDropFrameTestChannel *>(channel_)->IncreaseCheckVariableCounter();
42 TestUtil::SuspendUntilContinue(DebugEvent::CHECK_COMPLETE);
43 DropFrameIfChecked();
44 TestUtil::SuspendUntilContinue(DebugEvent::DROPFRAME);
45 return true;
46 }
47 return false;
48 };
49
50 loadModule = [this](std::string_view moduleName) {
51 static_cast<JsDropFrameTestChannel *>(channel_)->Initial(vm_, runtime_);
52 runtime_->Enable();
53 size_t breakpoint[POINTER_SIZE][LINE_COLUMN] =
54 {{26, 0}, {42, 0}, {57, 0}, {69, 0}, {87, 0}, {100, 0}, {117, 0},
55 {143, 0}, {151, 0}, {164, 0}, {172, 0}, {182, 0}, {192, 0}, {206, 0},
56 {217, 0}, {224, 0}, {230, 0}}; // 0-based
57 SetJSPtLocation(breakpoint[0], POINTER_SIZE, pointerLocations_);
58 InitBreakpointOpQueue();
59 TestUtil::SuspendUntilContinue(DebugEvent::LOAD_MODULE);
60 ASSERT_EQ(moduleName, pandaFile_);
61 ASSERT_TRUE(debugger_->NotifyScriptParsed(0, pandaFile_));
62 auto condFuncRef = FunctionRef::Undefined(vm_);
63 for (auto &iter : pointerLocations_) {
64 auto ret = debugInterface_->SetBreakpoint(iter, condFuncRef);
65 ASSERT_TRUE(ret);
66 }
67 return true;
68 };
69
70 scenario = [this]() {
71 TestUtil::WaitForLoadModule();
72 TestUtil::Continue();
73 for (size_t index = 0; index < POINTER_SIZE; index++) {
74 for (size_t hitCount = 0; hitCount < breakpointHitTimes[index]; hitCount++) {
75 TestUtil::WaitForBreakpoint(pointerLocations_.at(index));
76 if (hitCount == breakpointHitTimes[index] - 1) {
77 auto ret = debugInterface_->RemoveBreakpoint(pointerLocations_.at(index));
78 ASSERT_TRUE(ret);
79 }
80 TestUtil::Continue();
81 while (dropFrameChecked_) {
82 dropFrameChecked_ = false;
83 TestUtil::WaitForCheckComplete();
84 TestUtil::Continue();
85 TestUtil::WaitForDropframe();
86 dropframeCounter_++;
87 TestUtil::Continue();
88 }
89 }
90 }
91 ASSERT_EXITED();
92 return true;
93 };
94
95 vmDeath = [this]() {
96 ASSERT_EQ(breakpointCounter_, 59U); // a total of 59 times hitting breakpoints
97 ASSERT_EQ(dropframeCounter_, 47U); // a total of 47 times dropping frames
98 return true;
99 };
100 }
101
GetEntryPoint()102 std::pair<std::string, std::string> GetEntryPoint() override
103 {
104 return {pandaFile_, entryPoint_};
105 }
~JsDropFrameTest()106 ~JsDropFrameTest()
107 {
108 delete channel_;
109 channel_ = nullptr;
110 }
111
112 private:
113 class JsDropFrameTestChannel : public TestChannel {
114 public:
115 JsDropFrameTestChannel() = default;
116 ~JsDropFrameTestChannel() = default;
Initial(const EcmaVM * vm,RuntimeImpl * runtime)117 void Initial(const EcmaVM *vm, RuntimeImpl *runtime)
118 {
119 vm_ = vm;
120 runtime_ = runtime;
121 }
122
SendNotification(const PtBaseEvents & events)123 void SendNotification(const PtBaseEvents &events) override
124 {
125 const static std::vector<std::function<bool(const PtBaseEvents &events)>> eventList = {
126 [](const PtBaseEvents &events) -> bool {
127 std::string sourceFile = DEBUGGER_JS_DIR "dropframe.js";
128 auto parsed = static_cast<const ScriptParsed *>(&events);
129 ASSERT_EQ(parsed->GetName(), "Debugger.scriptParsed");
130 ASSERT_EQ(parsed->GetUrl(), sourceFile);
131 return true;
132 },
133 [this](const PtBaseEvents &events) -> bool {
134 std::cout << checkVariableCounter_ << std::endl;
135 auto paused = static_cast<const Paused *>(&events);
136 ASSERT_EQ(paused->GetName(), "Debugger.paused");
137 auto allFrames = paused->GetCallFrames();
138 std::map<std::string, std::string> truthVariableMap = variableMap_.at(checkVariableCounter_);
139 for (size_t index = 0; index < allFrames->size(); index++) {
140 auto frame = paused->GetCallFrames()->at(index).get();
141 auto scopes = frame->GetScopeChain();
142 for (uint32_t i = 0; i < scopes->size(); i++) {
143 auto scope = scopes->at(i).get();
144 std::string scopeType = scope->GetType();
145 if (scopeType != Scope::Type::Local() && scopeType != Scope::Type::Closure()) {
146 continue;
147 }
148 auto localId = scope->GetObject()->GetObjectId();
149 GetPropertiesParams params;
150 params.SetObjectId(localId).SetOwnProperties(true);
151 std::vector<std::unique_ptr<PropertyDescriptor>> outPropertyDesc;
152 runtime_->GetProperties(params, &outPropertyDesc, {}, {}, {});
153 for (const auto &property : outPropertyDesc) {
154 std::cout << "=====================================" << std::endl;
155 std::string name = property->GetName();
156 std::cout << name << std::endl;
157 if (truthVariableMap.count(name)) {
158 auto value = property->GetValue();
159 if (value->HasValue()) {
160 std::string valueStr = value->GetValue()->ToString(vm_)->ToString(vm_);
161 std::cout << valueStr << std::endl;
162 ASSERT_EQ(valueStr, truthVariableMap[name]);
163 }
164 }
165 }
166 }
167 }
168 return true;
169 }
170 };
171
172 ASSERT_TRUE(eventList[index_](events));
173 index_ |= 1;
174 }
175
IncreaseCheckVariableCounter()176 void IncreaseCheckVariableCounter()
177 {
178 checkVariableCounter_++;
179 }
180
181 private:
182 NO_COPY_SEMANTIC(JsDropFrameTestChannel);
183 NO_MOVE_SEMANTIC(JsDropFrameTestChannel);
184
185 const std::vector<std::map<std::string, std::string>> variableMap_ = {
186 { { "a", "2" }, { "b", "3" }, { "c", "4" }, {"d", "2"} },
187 { { "a", "2" }, { "b", "3" }, { "c", "3" }, {"d", "1"} },
188 { { "a", "2" }, { "b", "2" }, { "c", "3" }, {"d", "0"} },
189 { { "a", "1" }, { "b", "2" }, { "c", "3" } },
190 { { "a", "2" }, { "b", "3" }, { "c", "4" }, {"d", "2"} },
191 { { "a", "4" }, { "b", "5" }, { "c", "6" }, {"d", "2"} },
192 { { "a", "6" }, { "b", "4" }, { "c", "5" }, {"d", "2"} },
193 { { "a", "6" }, { "b", "4" }, { "c", "5" }, {"d", "1"} },
194 { { "a", "2" }, { "b", "3" }, { "c", "4" } },
195 { { "a", "4" }, { "b", "5" }, { "c", "6" }, {"d", "2"} },
196 { { "a", "8" }, { "b", "13" }, { "c", "78" }, {"d", "1"} },
197 { { "a", "4" }, { "b", "5" }, { "c", "6" }, {"d", "1"} },
198 { { "a", "8" }, { "b", "13" }, { "c", "78" }, {"d", "1"} },
199 { { "a", "16" }, { "b", "29" }, { "c", "2262" }, {"d", "182"} },
200 { { "a", "8" }, { "b", "13" }, { "c", "78" }, {"d", "182"} },
201 { { "a", "4" }, { "b", "5" }, { "c", "6" } },
202 { { "a", "8" }, { "b", "13" }, { "c", "78" }, {"d", "1"} },
203 { { "a", "32" }, { "b", "61" }, { "c", "4214" }, {"d", "1"} },
204 { { "a", "16" }, { "b", "29" }, { "c", "2262" }, {"d", "1"} },
205 { { "a", "32" }, { "b", "61" }, { "c", "4214" }, {"d", "1"} },
206 { { "a", "64" }, { "b", "125" }, { "c", "12214" }, {"d", "29"} },
207 { { "a", "128" }, { "b", "253" }, { "c", "44598" }, {"d", "1769"} },
208 { { "a", "256" }, { "b", "509" }, { "c", "174902" }, {"d", "221125"} },
209 { { "a", "128" }, { "b", "253" }, { "c", "44598" }, {"d", "221125"} },
210 { { "a", "16" }, { "b", "29" }, { "c", "2262" } },
211 { { "a", "32" }, { "b", "61" }, { "c", "4214" }, {"d", "1"} },
212 { { "a", "256" }, { "b", "1277" }, { "c", "176435" } },
213 { { "a", "256" }, { "b", "509" }, { "c", "174902" } },
214 { { "a", "256" }, { "b", "509" }, { "c", "174902" } },
215 { { "a", "256" }, { "b", "1277" }, { "c", "176435" } },
216 { { "a", "256" }, { "b", "2301" }, { "c", "178992" } },
217 { { "a", "512" }, { "b", "3837" }, { "c", "183341" } },
218 { { "a", "1024" }, { "b", "7933" }, { "c", "192298" } },
219 { { "a", "512" }, { "b", "3837" }, { "c", "183341" } },
220 { { "a", "1024" }, { "b", "7933" }, { "c", "192298" } },
221 { { "a", "1024" }, { "b", "7933" }, { "c", "192298" }, {"s", "2"} },
222 { { "a", "1024" }, { "b", "7933" }, { "c", "192298" }, {"s", "2"} },
223 { { "a", "1024" }, { "b", "7933" }, { "c", "192298" } },
224 { { "a", "1024" }, { "b", "7933" }, { "c", "192298" } },
225 { { "a", "1024" }, { "b", "7933" }, { "c", "192298" } },
226 { { "a", "1024" }, { "b", "7933" }, { "c", "192298" }, {"s", "2"} },
227 { { "a", "1024" }, { "b", "7933" }, { "c", "192298" }, {"s", "3"} },
228 { { "a", "1024" }, { "b", "7933" }, { "c", "192298" } },
229 { { "a", "1024" }, { "b", "7933" }, { "c", "192298" }, {"s", "3"} },
230 { { "a", "10" }, { "b", "7933" }, { "c", "192298" }, {"x", "7"} },
231 { { "a", "9" }, { "b", "7933" }, { "c", "192298" }, {"x", "7"} },
232 { { "a", "8" }, { "b", "7933" }, { "c", "192298" }, {"x", "7"} },
233 { { "a", "10" }, { "b", "7933" }, { "c", "192298" }, {"x", "7"} },
234 { { "a", "11" }, { "b", "7933" }, { "c", "192298" }, {"x", "7"} },
235 { { "a", "12" }, { "b", "7933" }, { "c", "192298" }, {"x", "7"} },
236 { { "a", "7" }, { "b", "7933" }, { "c", "192298" }, {"x", "7"} },
237 { { "a", "10" }, { "b", "7933" }, { "c", "192298" }, {"x", "7"} },
238 { { "a", "19" }, { "b", "2" }, { "c", "3" }, {"d", "1"} },
239 { { "a", "19" }, { "b", "2" }, { "c", "3" }, {"d", "1"} },
240 { { "a", "19" }, { "b", "2" }, { "c", "3" }, {"d", "1"} },
241 { { "a", "20" }, { "b", "3" }, { "c", "4" }, {"d", "3"} },
242 { { "a", "19" }, { "b", "2" }, { "c", "3" }, {"d", "2"} },
243 { { "a", "20" }, { "b", "3" }, { "c", "4" }, {"d", "3"} },
244 { { "a", "23" }, { "b", "6" }, { "c", "7" }, {"d", "7"} },
245 { { "a", "20" }, { "b", "3" }, { "c", "4" }, {"d", "4"} },
246 { { "a", "23" }, { "b", "6" }, { "c", "7" }, {"d", "7"} },
247 { { "a", "29" }, { "b", "12" }, { "c", "13" }, {"d", "14"} },
248 { { "a", "39" }, { "b", "22" }, { "c", "23" }, {"d", "25"} },
249 { { "a", "29" }, { "b", "12" }, { "c", "13" }, {"d", "15"} },
250 { { "a", "39" }, { "b", "22" }, { "c", "23" }, {"d", "25"} },
251 { { "a", "54" }, { "b", "37" }, { "c", "38" }, {"d", "41"} },
252 { { "a", "54" }, { "b", "37" }, { "c", "38" }, {"d", "42"} },
253 { { "a", "19" }, { "b", "2" }, { "c", "3" } },
254 { { "a", "54" }, { "b", "37" }, { "c", "38" }, {"d", "42"} },
255 { { "a", "76" }, { "b", "60" }, { "c", "62" }, {"d", "1"}, {"e", "77"} },
256 { { "a", "75" }, { "b", "58" }, { "c", "59" }, {"d", "1"}, {"e", "1"} },
257 { { "a", "75" }, { "b", "58" }, { "c", "59" }, {"d", "1"} },
258 { { "a", "75" }, { "b", "58" }, { "c", "59" } },
259 { { "a", "76" }, { "b", "60" }, { "c", "62" }, {"d", "1"}, {"e", "77"} },
260 { { "a", "81" }, { "b", "65" }, { "c", "67" }, {"d", "5"} },
261 { { "a", "76" }, { "b", "60" }, { "c", "62" }, {"d", "5"} },
262 { { "a", "75" }, { "b", "58" }, { "c", "59" } },
263 { { "a", "81" }, { "b", "65" }, { "c", "67" }, {"d", "5"} },
264 { { "a", "87" }, { "b", "71" }, { "c", "73" }, {"d", "6"} },
265 { { "a", "81" }, { "b", "65" }, { "c", "67" }, {"d", "6"} },
266 { { "a", "87" }, { "b", "71" }, { "c", "73" }, {"d", "6"} },
267 { { "a", "88" }, { "b", "73" }, { "c", "76" }, {"d", "7"}, {"e", "84"} },
268 { { "a", "87" }, { "b", "71" }, { "c", "73" }, {"d", "7"}, {"e", "1"} },
269 { { "a", "87" }, { "b", "71" }, { "c", "73" }, {"d", "7"} },
270 { { "a", "75" }, { "b", "58" }, { "c", "59" } },
271 { { "a", "88" }, { "b", "73" }, { "c", "76" }, {"d", "7"}, {"e", "84"} },
272 { { "a", "88" }, { "b", "73" }, { "c", "76" }, {"d", "11"} },
273 { { "a", "75" }, { "b", "58" }, { "c", "59" } },
274 { { "a", "88" }, { "b", "73" }, { "c", "76" }, {"d", "11"} },
275 { { "a", "6" }, { "b", "13" }, { "c", "3" }, {"d", "11"}, {"e", "11"} },
276 { { "a", "1" }, { "b", "2" }, { "c", "3" }, {"d", "10"}, {"e", "1"} },
277 { { "a", "1" }, { "b", "2" }, { "c", "3" }, {"d", "10"} },
278 { { "a", "1" }, { "b", "2" }, { "c", "3" }, {"d", "10"} },
279 { { "a", "1" }, { "b", "2" }, { "c", "3" } },
280 { { "a", "6" }, { "b", "13" }, { "c", "3" }, {"d", "11"}, {"e", "11"} },
281 { { "a", "7" }, { "b", "14" }, { "c", "14" }, {"d", "11"} },
282 { { "a", "1" }, { "b", "2" }, { "c", "3" }, {"d", "10"} },
283 { { "a", "1" }, { "b", "2" }, { "c", "3" } },
284 { { "a", "7" }, { "b", "14" }, { "c", "14" }, {"d", "11"} },
285 { { "a", "8" }, { "b", "16" }, { "c", "18" }, {"d", "11"} },
286 { { "a", "7" }, { "b", "14" }, { "c", "15" }, {"d", "11"} },
287 { { "a", "1" }, { "b", "2" }, { "c", "3" } },
288 { { "a", "8" }, { "b", "16" }, { "c", "18" }, {"d", "11"} },
289 { { "a", "8" }, { "b", "16" }, { "c", "18" }, {"d", "19"} },
290 { { "a", "1" }, { "b", "2" }, { "c", "3" } },
291 { { "a", "8" }, { "b", "16" }, { "c", "18" }, {"d", "19"} }
292 };
293
294 int32_t index_ {0};
295 const EcmaVM *vm_ {nullptr};
296 RuntimeImpl *runtime_ {nullptr};
297 size_t checkVariableCounter_ {0};
298 };
299
300 enum breakpointOpType {
301 RESUME = 1,
302 DROPLASTFRAME = 2
303 };
304
305 static constexpr size_t LINE_COLUMN = 2;
306 static constexpr size_t POINTER_SIZE = 17;
307
308 std::string pandaFile_ = DEBUGGER_ABC_DIR "dropframe.abc";
309 std::string sourceFile_ = DEBUGGER_JS_DIR "dropframe.js";
310 std::string entryPoint_ = "_GLOBAL::func_main_0";
311 size_t breakpointCounter_ = 0;
312 size_t dropframeCounter_ = 0;
313 bool dropFrameChecked_ = false;
314 std::vector<JSPtLocation> pointerLocations_;
315 size_t breakpointHitTimes[POINTER_SIZE] = {2, 2, 4, 6, 6, 4, 5, 10, 2, 2, 4, 2, 2, 2, 2, 2, 2};
316 std::queue<std::pair<uint8_t, uint8_t>> breakpointOp;
317
InitBreakpointOpQueue()318 void InitBreakpointOpQueue()
319 {
320 breakpointOp.push({1, breakpointOpType::DROPLASTFRAME});
321 breakpointOp.push({1, breakpointOpType::DROPLASTFRAME});
322 breakpointOp.push({1, breakpointOpType::DROPLASTFRAME});
323 breakpointOp.push({3, breakpointOpType::DROPLASTFRAME});
324 breakpointOp.push({3, breakpointOpType::DROPLASTFRAME});
325 breakpointOp.push({3, breakpointOpType::DROPLASTFRAME});
326 breakpointOp.push({5, breakpointOpType::DROPLASTFRAME});
327 breakpointOp.push({7, breakpointOpType::DROPLASTFRAME});
328 breakpointOp.push({7, breakpointOpType::DROPLASTFRAME});
329 breakpointOp.push({9, breakpointOpType::DROPLASTFRAME});
330 breakpointOp.push({13, breakpointOpType::DROPLASTFRAME});
331 breakpointOp.push({13, breakpointOpType::DROPLASTFRAME});
332 breakpointOp.push({15, breakpointOpType::DROPLASTFRAME});
333 breakpointOp.push({15, breakpointOpType::DROPLASTFRAME});
334 breakpointOp.push({19, breakpointOpType::DROPLASTFRAME});
335 breakpointOp.push({21, breakpointOpType::DROPLASTFRAME});
336 breakpointOp.push({21, breakpointOpType::DROPLASTFRAME});
337 breakpointOp.push({21, breakpointOpType::DROPLASTFRAME});
338 breakpointOp.push({21, breakpointOpType::DROPLASTFRAME});
339 breakpointOp.push({23, breakpointOpType::DROPLASTFRAME});
340 breakpointOp.push({25, breakpointOpType::DROPLASTFRAME});
341 breakpointOp.push({25, breakpointOpType::DROPLASTFRAME});
342 breakpointOp.push({28, breakpointOpType::DROPLASTFRAME});
343 breakpointOp.push({30, breakpointOpType::DROPLASTFRAME});
344 breakpointOp.push({32, breakpointOpType::DROPLASTFRAME});
345 breakpointOp.push({34, breakpointOpType::DROPLASTFRAME});
346 breakpointOp.push({37, breakpointOpType::DROPLASTFRAME});
347 breakpointOp.push({40, breakpointOpType::DROPLASTFRAME});
348 breakpointOp.push({42, breakpointOpType::DROPLASTFRAME});
349 breakpointOp.push({42, breakpointOpType::DROPLASTFRAME});
350 breakpointOp.push({42, breakpointOpType::DROPLASTFRAME});
351 breakpointOp.push({44, breakpointOpType::DROPLASTFRAME});
352 breakpointOp.push({44, breakpointOpType::DROPLASTFRAME});
353 breakpointOp.push({46, breakpointOpType::DROPLASTFRAME});
354 breakpointOp.push({48, breakpointOpType::DROPLASTFRAME});
355 breakpointOp.push({48, breakpointOpType::DROPLASTFRAME});
356 breakpointOp.push({48, breakpointOpType::DROPLASTFRAME});
357 breakpointOp.push({50, breakpointOpType::DROPLASTFRAME});
358 breakpointOp.push({52, breakpointOpType::DROPLASTFRAME});
359 breakpointOp.push({52, breakpointOpType::DROPLASTFRAME});
360 breakpointOp.push({52, breakpointOpType::DROPLASTFRAME});
361 breakpointOp.push({52, breakpointOpType::DROPLASTFRAME});
362 breakpointOp.push({54, breakpointOpType::DROPLASTFRAME});
363 breakpointOp.push({54, breakpointOpType::DROPLASTFRAME});
364 breakpointOp.push({56, breakpointOpType::DROPLASTFRAME});
365 breakpointOp.push({56, breakpointOpType::DROPLASTFRAME});
366 breakpointOp.push({58, breakpointOpType::DROPLASTFRAME});
367 }
368
DropFrameIfChecked()369 void DropFrameIfChecked()
370 {
371 while (!dropFrameChecked_ && !breakpointOp.empty() && breakpointOp.front().first == breakpointCounter_) {
372 if (breakpointOp.front().second == breakpointOpType::DROPLASTFRAME) {
373 PtJson paramsJson;
374 paramsJson.Add("droppedDepth", 1U);
375 std::unique_ptr<DropFrameParams> params = DropFrameParams::Create(paramsJson);
376 debugger_->DropFrame(*params);
377 dropFrameChecked_ = true;
378 }
379 breakpointOp.pop();
380 }
381 }
382
SetJSPtLocation(size_t * arr,size_t number,std::vector<JSPtLocation> & locations)383 void SetJSPtLocation(size_t *arr, size_t number, std::vector<JSPtLocation> &locations)
384 {
385 for (size_t i = 0; i < number; i++) {
386 JSPtLocation location = TestUtil::GetLocation(sourceFile_.c_str(), arr[i * LINE_COLUMN],
387 arr[i * LINE_COLUMN + 1], pandaFile_.c_str());
388 locations.push_back(location);
389 }
390 };
391 };
392
GetJsDropFrameTest()393 std::unique_ptr<TestEvents> GetJsDropFrameTest()
394 {
395 return std::make_unique<JsDropFrameTest>();
396 }
397 } // namespace panda::ecmascript::tooling::test
398
399 #endif // ECMASCRIPT_TOOLING_TEST_UTILS_TESTCASES_JS_DROP_FRAME_TEST_H
400