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 #include "ecmascript/debugger/debugger_api.h"
17
18 #include "ecmascript/base/number_helper.h"
19 #include "ecmascript/debugger/js_debugger.h"
20 #include "ecmascript/ecma_macros.h"
21 #include "ecmascript/interpreter/frame_handler.h"
22 #include "ecmascript/interpreter/slow_runtime_stub.h"
23 #include "ecmascript/interpreter/fast_runtime_stub-inl.h"
24 #include "ecmascript/jspandafile/js_pandafile_executor.h"
25 #include "ecmascript/jspandafile/program_object.h"
26 #include "ecmascript/js_handle.h"
27 #include "ecmascript/jspandafile/js_pandafile_manager.h"
28 #include "ecmascript/method.h"
29 #include "ecmascript/module/js_module_manager.h"
30 #include "ecmascript/module/js_module_source_text.h"
31 #include "ecmascript/napi/jsnapi_helper.h"
32 #include "ecmascript/tagged_array.h"
33 #include "ecmascript/tagged_dictionary.h"
34 #include "ecmascript/tagged_hash_array.h"
35 #include "ecmascript/tagged_tree.h"
36 #include "ecmascript/tagged_queue.h"
37 #include "ecmascript/js_api/js_api_hashmap.h"
38 #include "ecmascript/js_api/js_api_hashset.h"
39 #include "ecmascript/js_api/js_api_tree_map.h"
40 #include "ecmascript/js_api/js_api_tree_set.h"
41 #include "ecmascript/js_api/js_api_lightweightmap.h"
42 #include "ecmascript/js_api/js_api_lightweightset.h"
43 #include "ecmascript/frames.h"
44
45 namespace panda::ecmascript::tooling {
46 using panda::ecmascript::base::ALLOW_BINARY;
47 using panda::ecmascript::base::ALLOW_HEX;
48 using panda::ecmascript::base::ALLOW_OCTAL;
49 using panda::ecmascript::base::NumberHelper;
50 using ecmascript::JSAPIArrayList;
51 using ecmascript::JSAPIDeque;
52 using ecmascript::JSAPIHashMap;
53 using ecmascript::JSAPIHashSet;
54 using ecmascript::JSAPILightWeightMap;
55 using ecmascript::JSAPILightWeightSet;
56 using ecmascript::JSAPIList;
57 using ecmascript::JSAPILinkedList;
58 using ecmascript::JSAPIPlainArray;
59 using ecmascript::JSAPIStack;
60 using ecmascript::JSAPIQueue;
61 using ecmascript::JSAPITreeSet;
62 using ecmascript::JSAPITreeMap;
63 using ecmascript::JSAPIVector;
64 using ecmascript::LinkedNode;
65 using ecmascript::TaggedHashArray;
66 using ecmascript::TaggedNode;
67 using ecmascript::RBTreeNode;
68 using ecmascript::TaggedTreeSet;
69 using ecmascript::TaggedTreeMap;
70 using ecmascript::TaggedQueue;
71
72 // FrameHandler
GetStackDepth(const EcmaVM * ecmaVm)73 uint32_t DebuggerApi::GetStackDepth(const EcmaVM *ecmaVm)
74 {
75 uint32_t count = 0;
76 FrameHandler frameHandler(ecmaVm->GetJSThread());
77 for (; frameHandler.HasFrame(); frameHandler.PrevJSFrame()) {
78 if (frameHandler.IsEntryFrame() || frameHandler.IsBuiltinFrame()) {
79 continue;
80 }
81 ++count;
82 }
83 return count;
84 }
85
NewFrameHandler(const EcmaVM * ecmaVm)86 std::shared_ptr<FrameHandler> DebuggerApi::NewFrameHandler(const EcmaVM *ecmaVm)
87 {
88 return std::make_shared<FrameHandler>(ecmaVm->GetJSThread());
89 }
90
StackWalker(const EcmaVM * ecmaVm,std::function<StackState (const FrameHandler *)> func)91 bool DebuggerApi::StackWalker(const EcmaVM *ecmaVm, std::function<StackState(const FrameHandler *)> func)
92 {
93 FrameHandler frameHandler(ecmaVm->GetJSThread());
94 for (; frameHandler.HasFrame(); frameHandler.PrevJSFrame()) {
95 if (frameHandler.IsEntryFrame() || frameHandler.IsBuiltinFrame()) {
96 continue;
97 }
98 StackState state = func(&frameHandler);
99 if (state == StackState::CONTINUE) {
100 continue;
101 }
102 if (state == StackState::FAILED) {
103 return false;
104 }
105 return true;
106 }
107 return true;
108 }
109
GetBytecodeOffset(const EcmaVM * ecmaVm)110 uint32_t DebuggerApi::GetBytecodeOffset(const EcmaVM *ecmaVm)
111 {
112 return FrameHandler(ecmaVm->GetJSThread()).GetBytecodeOffset();
113 }
114
GetMethod(const EcmaVM * ecmaVm)115 std::unique_ptr<PtMethod> DebuggerApi::GetMethod(const EcmaVM *ecmaVm)
116 {
117 FrameHandler frameHandler(ecmaVm->GetJSThread());
118 Method* method = frameHandler.GetMethod();
119 std::unique_ptr<PtMethod> ptMethod = std::make_unique<PtMethod>(
120 method->GetJSPandaFile(), method->GetMethodId(), method->IsNativeWithCallField());
121 return ptMethod;
122 }
123
SetVRegValue(FrameHandler * frameHandler,size_t index,Local<JSValueRef> value)124 void DebuggerApi::SetVRegValue(FrameHandler *frameHandler, size_t index, Local<JSValueRef> value)
125 {
126 return frameHandler->SetVRegValue(index, JSNApiHelper::ToJSTaggedValue(*value));
127 }
128
GetBytecodeOffset(const FrameHandler * frameHandler)129 uint32_t DebuggerApi::GetBytecodeOffset(const FrameHandler *frameHandler)
130 {
131 return frameHandler->GetBytecodeOffset();
132 }
133
GetMethod(const FrameHandler * frameHandler)134 Method *DebuggerApi::GetMethod(const FrameHandler *frameHandler)
135 {
136 return frameHandler->GetMethod();
137 }
138
IsNativeMethod(const EcmaVM * ecmaVm)139 bool DebuggerApi::IsNativeMethod(const EcmaVM *ecmaVm)
140 {
141 FrameHandler frameHandler(ecmaVm->GetJSThread());
142 return DebuggerApi::IsNativeMethod(&frameHandler);
143 }
144
IsNativeMethod(const FrameHandler * frameHandler)145 bool DebuggerApi::IsNativeMethod(const FrameHandler *frameHandler)
146 {
147 if (!frameHandler->HasFrame()) {
148 return false;
149 }
150 Method* method = frameHandler->GetMethod();
151 return method->IsNativeWithCallField();
152 }
153
GetJSPandaFile(const EcmaVM * ecmaVm)154 JSPandaFile *DebuggerApi::GetJSPandaFile(const EcmaVM *ecmaVm)
155 {
156 Method *method = FrameHandler(ecmaVm->GetJSThread()).GetMethod();
157 return const_cast<JSPandaFile *>(method->GetJSPandaFile());
158 }
159
GetEnv(const FrameHandler * frameHandler)160 JSTaggedValue DebuggerApi::GetEnv(const FrameHandler *frameHandler)
161 {
162 return frameHandler->GetEnv();
163 }
164
GetSp(const FrameHandler * frameHandler)165 JSTaggedType *DebuggerApi::GetSp(const FrameHandler *frameHandler)
166 {
167 return frameHandler->GetSp();
168 }
169
GetVregIndex(const FrameHandler * frameHandler,std::string_view name)170 int32_t DebuggerApi::GetVregIndex(const FrameHandler *frameHandler, std::string_view name)
171 {
172 Method *method = DebuggerApi::GetMethod(frameHandler);
173 if (method->IsNativeWithCallField()) {
174 LOG_DEBUGGER(ERROR) << "GetVregIndex: native frame not support";
175 return -1;
176 }
177 DebugInfoExtractor *extractor = JSPandaFileManager::GetInstance()->GetJSPtExtractor(method->GetJSPandaFile());
178 if (extractor == nullptr) {
179 LOG_DEBUGGER(ERROR) << "GetVregIndex: extractor is null";
180 return -1;
181 }
182 auto table = extractor->GetLocalVariableTable(method->GetMethodId());
183 for (auto iter = table.begin(); iter != table.end(); iter++) {
184 if (iter->name == name.data()) {
185 return iter->regNumber;
186 }
187 }
188 return -1;
189 }
190
GetVRegValue(const EcmaVM * ecmaVm,const FrameHandler * frameHandler,size_t index)191 Local<JSValueRef> DebuggerApi::GetVRegValue(const EcmaVM *ecmaVm,
192 const FrameHandler *frameHandler, size_t index)
193 {
194 auto value = frameHandler->GetVRegValue(index);
195 JSHandle<JSTaggedValue> handledValue(ecmaVm->GetJSThread(), value);
196 return JSNApiHelper::ToLocal<JSValueRef>(handledValue);
197 }
198
199 // JSThread
GetAndClearException(const EcmaVM * ecmaVm)200 Local<JSValueRef> DebuggerApi::GetAndClearException(const EcmaVM *ecmaVm)
201 {
202 auto exception = ecmaVm->GetJSThread()->GetException();
203 JSHandle<JSTaggedValue> handledException(ecmaVm->GetJSThread(), exception);
204 ecmaVm->GetJSThread()->ClearException();
205 return JSNApiHelper::ToLocal<JSValueRef>(handledException);
206 }
207
SetException(const EcmaVM * ecmaVm,Local<JSValueRef> exception)208 void DebuggerApi::SetException(const EcmaVM *ecmaVm, Local<JSValueRef> exception)
209 {
210 ecmaVm->GetJSThread()->SetException(JSNApiHelper::ToJSTaggedValue(*exception));
211 }
212
ClearException(const EcmaVM * ecmaVm)213 void DebuggerApi::ClearException(const EcmaVM *ecmaVm)
214 {
215 return ecmaVm->GetJSThread()->ClearException();
216 }
217
218 // NumberHelper
StringToDouble(const uint8_t * start,const uint8_t * end,uint8_t radix)219 double DebuggerApi::StringToDouble(const uint8_t *start, const uint8_t *end, uint8_t radix)
220 {
221 return NumberHelper::StringToDouble(start, end, radix, ALLOW_BINARY | ALLOW_HEX | ALLOW_OCTAL);
222 }
223
224 // JSDebugger
CreateJSDebugger(const EcmaVM * ecmaVm)225 JSDebugger *DebuggerApi::CreateJSDebugger(const EcmaVM *ecmaVm)
226 {
227 return new JSDebugger(ecmaVm);
228 }
229
DestroyJSDebugger(JSDebugger * debugger)230 void DebuggerApi::DestroyJSDebugger(JSDebugger *debugger)
231 {
232 delete debugger;
233 }
234
RegisterHooks(JSDebugger * debugger,PtHooks * hooks)235 void DebuggerApi::RegisterHooks(JSDebugger *debugger, PtHooks *hooks)
236 {
237 debugger->RegisterHooks(hooks);
238 }
239
SetBreakpoint(JSDebugger * debugger,const JSPtLocation & location,Local<FunctionRef> condFuncRef)240 bool DebuggerApi::SetBreakpoint(JSDebugger *debugger, const JSPtLocation &location,
241 Local<FunctionRef> condFuncRef)
242 {
243 return debugger->SetBreakpoint(location, condFuncRef);
244 }
245
RemoveBreakpoint(JSDebugger * debugger,const JSPtLocation & location)246 bool DebuggerApi::RemoveBreakpoint(JSDebugger *debugger, const JSPtLocation &location)
247 {
248 return debugger->RemoveBreakpoint(location);
249 }
250
RemoveAllBreakpoints(JSDebugger * debugger)251 void DebuggerApi::RemoveAllBreakpoints(JSDebugger *debugger)
252 {
253 return debugger->RemoveAllBreakpoints();
254 }
255
256 // ScopeInfo
GetProperties(const EcmaVM * ecmaVm,const FrameHandler * frameHandler,int32_t level,uint32_t slot)257 Local<JSValueRef> DebuggerApi::GetProperties(const EcmaVM *ecmaVm, const FrameHandler *frameHandler,
258 int32_t level, uint32_t slot)
259 {
260 JSTaggedValue env = frameHandler->GetEnv();
261 for (int i = 0; i < level; i++) {
262 JSTaggedValue taggedParentEnv = LexicalEnv::Cast(env.GetTaggedObject())->GetParentEnv();
263 ASSERT(!taggedParentEnv.IsUndefined());
264 env = taggedParentEnv;
265 }
266 JSTaggedValue value = LexicalEnv::Cast(env.GetTaggedObject())->GetProperties(slot);
267 JSHandle<JSTaggedValue> handledValue(ecmaVm->GetJSThread(), value);
268 return JSNApiHelper::ToLocal<JSValueRef>(handledValue);
269 }
270
SetProperties(const EcmaVM * ecmaVm,const FrameHandler * frameHandler,int32_t level,uint32_t slot,Local<JSValueRef> value)271 void DebuggerApi::SetProperties(const EcmaVM *ecmaVm, const FrameHandler *frameHandler,
272 int32_t level, uint32_t slot, Local<JSValueRef> value)
273 {
274 JSTaggedValue env = frameHandler->GetEnv();
275 for (int i = 0; i < level; i++) {
276 JSTaggedValue taggedParentEnv = LexicalEnv::Cast(env.GetTaggedObject())->GetParentEnv();
277 ASSERT(!taggedParentEnv.IsUndefined());
278 env = taggedParentEnv;
279 }
280 JSTaggedValue target = JSNApiHelper::ToJSHandle(value).GetTaggedValue();
281 LexicalEnv::Cast(env.GetTaggedObject())->SetProperties(ecmaVm->GetJSThread(), slot, target);
282 }
283
GetLevelSlot(const FrameHandler * frameHandler,std::string_view name)284 std::pair<int32_t, uint32_t> DebuggerApi::GetLevelSlot(const FrameHandler *frameHandler, std::string_view name)
285 {
286 int32_t level = 0;
287 uint32_t slot = 0;
288 JSTaggedValue curEnv = frameHandler->GetEnv();
289 for (; curEnv.IsTaggedArray(); curEnv = LexicalEnv::Cast(curEnv.GetTaggedObject())->GetParentEnv(), level++) {
290 LexicalEnv *lexicalEnv = LexicalEnv::Cast(curEnv.GetTaggedObject());
291 if (lexicalEnv->GetScopeInfo().IsHole()) {
292 continue;
293 }
294 auto result = JSNativePointer::Cast(lexicalEnv->GetScopeInfo().GetTaggedObject())->GetExternalPointer();
295 ScopeDebugInfo *scopeDebugInfo = reinterpret_cast<ScopeDebugInfo *>(result);
296 auto iter = scopeDebugInfo->scopeInfo.find(name.data());
297 if (iter == scopeDebugInfo->scopeInfo.end()) {
298 continue;
299 }
300 slot = iter->second;
301 return std::make_pair(level, slot);
302 }
303 return std::make_pair(-1, 0);
304 }
305
GetGlobalValue(const EcmaVM * ecmaVm,Local<StringRef> name)306 Local<JSValueRef> DebuggerApi::GetGlobalValue(const EcmaVM *ecmaVm, Local<StringRef> name)
307 {
308 JSTaggedValue result;
309 JSTaggedValue globalObj = ecmaVm->GetGlobalEnv()->GetGlobalObject();
310 JSThread *thread = ecmaVm->GetJSThread();
311
312 JSTaggedValue key = JSNApiHelper::ToJSTaggedValue(*name);
313 JSTaggedValue globalRec = SlowRuntimeStub::LdGlobalRecord(thread, key);
314 if (!globalRec.IsUndefined()) {
315 ASSERT(globalRec.IsPropertyBox());
316 result = PropertyBox::Cast(globalRec.GetTaggedObject())->GetValue();
317 return JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread, result));
318 }
319
320 JSTaggedValue globalVar = FastRuntimeStub::GetGlobalOwnProperty(thread, globalObj, key);
321 if (!globalVar.IsHole()) {
322 return JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread, globalVar));
323 } else {
324 result = SlowRuntimeStub::TryLdGlobalByNameFromGlobalProto(thread, globalObj, key);
325 return JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread, result));
326 }
327
328 return Local<JSValueRef>();
329 }
330
SetGlobalValue(const EcmaVM * ecmaVm,Local<StringRef> name,Local<JSValueRef> value)331 bool DebuggerApi::SetGlobalValue(const EcmaVM *ecmaVm, Local<StringRef> name, Local<JSValueRef> value)
332 {
333 JSTaggedValue result;
334 JSTaggedValue globalObj = ecmaVm->GetGlobalEnv()->GetGlobalObject();
335 JSThread *thread = ecmaVm->GetJSThread();
336
337 JSTaggedValue key = JSNApiHelper::ToJSTaggedValue(*name);
338 JSTaggedValue newVal = JSNApiHelper::ToJSTaggedValue(*value);
339 JSTaggedValue globalRec = SlowRuntimeStub::LdGlobalRecord(thread, key);
340 if (!globalRec.IsUndefined()) {
341 result = SlowRuntimeStub::TryUpdateGlobalRecord(thread, key, newVal);
342 return !result.IsException();
343 }
344
345 JSTaggedValue globalVar = FastRuntimeStub::GetGlobalOwnProperty(thread, globalObj, key);
346 if (!globalVar.IsHole()) {
347 result = SlowRuntimeStub::StGlobalVar(thread, key, newVal);
348 return !result.IsException();
349 }
350
351 return false;
352 }
353
GetCurrentModule(const EcmaVM * ecmaVm)354 JSTaggedValue DebuggerApi::GetCurrentModule(const EcmaVM *ecmaVm)
355 {
356 JSThread *thread = ecmaVm->GetJSThread();
357 FrameHandler frameHandler(thread);
358 for (; frameHandler.HasFrame(); frameHandler.PrevJSFrame()) {
359 if (frameHandler.IsEntryFrame()) {
360 continue;
361 }
362 Method *method = frameHandler.GetMethod();
363 // Skip builtins method
364 if (method->IsNativeWithCallField()) {
365 continue;
366 }
367 JSTaggedValue func = frameHandler.GetFunction();
368 JSTaggedValue module = JSFunction::Cast(func.GetTaggedObject())->GetModule();
369 if (module.IsUndefined()) {
370 continue;
371 }
372 return module;
373 }
374 UNREACHABLE();
375 }
376
GetImportModule(const EcmaVM * ecmaVm,const JSHandle<JSTaggedValue> & currentModule,std::string & name)377 JSHandle<JSTaggedValue> DebuggerApi::GetImportModule(const EcmaVM *ecmaVm,
378 const JSHandle<JSTaggedValue> ¤tModule, std::string &name)
379 {
380 JSThread *thread = ecmaVm->GetJSThread();
381 JSMutableHandle<JSTaggedValue> importModule(thread, thread->GlobalConstants()->GetUndefined());
382 if (!currentModule->IsSourceTextModule()) {
383 return importModule;
384 }
385
386 JSTaggedValue importEntries = SourceTextModule::Cast(currentModule->GetTaggedObject())->GetImportEntries();
387 if (importEntries.IsUndefined()) {
388 return importModule;
389 }
390
391 JSHandle<TaggedArray> importArray(thread, TaggedArray::Cast(importEntries.GetTaggedObject()));
392 size_t importEntriesLen = importArray->GetLength();
393 JSHandle<JSTaggedValue> starString = thread->GlobalConstants()->GetHandledStarString();
394 JSMutableHandle<ImportEntry> ee(thread, thread->GlobalConstants()->GetUndefined());
395 JSMutableHandle<TaggedArray> environment(thread, thread->GlobalConstants()->GetUndefined());
396 for (size_t idx = 0; idx < importEntriesLen; idx++) {
397 ee.Update(importArray->Get(idx));
398 JSTaggedValue localName = ee->GetLocalName();
399 JSTaggedValue importName = ee->GetImportName();
400 // Skip 'import * as name from xxx'
401 if (localName.IsString() && !JSTaggedValue::SameValue(importName, starString.GetTaggedValue())) {
402 std::string varName = EcmaStringAccessor(localName).ToStdString();
403 if (varName != name) {
404 continue;
405 }
406 JSTaggedValue moduleEnvironment = SourceTextModule::Cast(
407 currentModule->GetTaggedObject())->GetEnvironment();
408 environment.Update(moduleEnvironment);
409 JSTaggedValue resolvedBinding = environment->Get(idx);
410 ResolvedIndexBinding *binding = ResolvedIndexBinding::Cast(resolvedBinding.GetTaggedObject());
411 importModule.Update(binding->GetModule());
412 name = EcmaStringAccessor(importName).ToStdString();
413 return importModule;
414 }
415 }
416 return importModule;
417 }
418
GetModuleVariableIndex(const EcmaVM * ecmaVm,const JSHandle<JSTaggedValue> & currentModule,std::string & name)419 int32_t DebuggerApi::GetModuleVariableIndex(const EcmaVM *ecmaVm, const JSHandle<JSTaggedValue> ¤tModule,
420 std::string &name)
421 {
422 if (!currentModule->IsSourceTextModule()) {
423 return -1;
424 }
425 JSTaggedValue dictionary = SourceTextModule::Cast(currentModule->GetTaggedObject())->GetNameDictionary();
426 if (dictionary.IsUndefined()) {
427 return -1;
428 }
429
430 JSThread *thread = ecmaVm->GetJSThread();
431 if (dictionary.IsTaggedArray()) {
432 JSTaggedValue localExportEntries = SourceTextModule::Cast(
433 currentModule->GetTaggedObject())->GetLocalExportEntries();
434 ASSERT(localExportEntries.IsTaggedArray());
435 JSHandle<TaggedArray> localExportArray(thread, TaggedArray::Cast(localExportEntries.GetTaggedObject()));
436 uint32_t exportEntriesLen = localExportArray->GetLength();
437 JSMutableHandle<LocalExportEntry> ee(thread, thread->GlobalConstants()->GetUndefined());
438 for (uint32_t idx = 0; idx < exportEntriesLen; idx++) {
439 ee.Update(localExportArray->Get(idx));
440 JSTaggedValue localKey = ee->GetLocalName();
441 JSTaggedValue exportKey = ee->GetExportName();
442 if (localKey.IsString() && exportKey.IsString()) {
443 std::string localName = EcmaStringAccessor(localKey).ToStdString();
444 std::string exportName = EcmaStringAccessor(exportKey).ToStdString();
445 if (localName == name || exportName == name) {
446 return idx;
447 }
448 }
449 }
450 }
451 return -1;
452 }
453
GetRequestModuleIndex(const EcmaVM * ecmaVm,JSTaggedValue moduleRequest,const JSHandle<JSTaggedValue> & currentModule)454 int32_t DebuggerApi::GetRequestModuleIndex(const EcmaVM *ecmaVm, JSTaggedValue moduleRequest,
455 const JSHandle<JSTaggedValue> ¤tModule)
456 {
457 if (!currentModule->IsSourceTextModule()) {
458 return -1;
459 }
460 JSThread *thread = ecmaVm->GetJSThread();
461 JSHandle<SourceTextModule> module(thread, SourceTextModule::Cast(currentModule->GetTaggedObject()));
462 JSHandle<JSTaggedValue> required(thread, moduleRequest);
463 JSHandle<TaggedArray> requestedModules(thread, module->GetRequestedModules());
464 uint32_t requestedModulesLen = requestedModules->GetLength();
465 for (uint32_t idx = 0; idx < requestedModulesLen; idx++) {
466 JSTaggedValue requestModule = requestedModules->Get(idx);
467 if (JSTaggedValue::SameValue(required.GetTaggedValue(), requestModule)) {
468 return idx;
469 }
470 }
471 LOG_ECMA(FATAL) << "this branch is unreachable";
472 return -1;
473 }
474
GetExportVariableValue(const EcmaVM * ecmaVm,const JSHandle<JSTaggedValue> & currentModule,std::string & name)475 Local<JSValueRef> DebuggerApi::GetExportVariableValue(const EcmaVM *ecmaVm,
476 const JSHandle<JSTaggedValue> ¤tModule, std::string &name)
477 {
478 Local<JSValueRef> result;
479 if (!currentModule->IsSourceTextModule()) {
480 return result;
481 }
482 int32_t index = GetModuleVariableIndex(ecmaVm, currentModule, name);
483 if (index == -1) {
484 return result;
485 }
486
487 JSTaggedValue dictionary = SourceTextModule::Cast(currentModule->GetTaggedObject())->GetNameDictionary();
488 if (dictionary.IsUndefined()) {
489 return result;
490 }
491
492 JSThread *thread = ecmaVm->GetJSThread();
493 if (dictionary.IsTaggedArray()) {
494 TaggedArray *array = TaggedArray::Cast(dictionary.GetTaggedObject());
495 JSTaggedValue moduleValue = array->Get(index);
496 result = JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread, moduleValue));
497 return result;
498 }
499 return result;
500 }
501
SetExportVariableValue(const EcmaVM * ecmaVm,const JSHandle<JSTaggedValue> & currentModule,std::string & name,Local<JSValueRef> value)502 bool DebuggerApi::SetExportVariableValue(const EcmaVM *ecmaVm, const JSHandle<JSTaggedValue> ¤tModule,
503 std::string &name, Local<JSValueRef> value)
504 {
505 if (!currentModule->IsSourceTextModule()) {
506 return false;
507 }
508 int32_t index = GetModuleVariableIndex(ecmaVm, currentModule, name);
509 if (index == -1) {
510 return false;
511 }
512
513 JSTaggedValue dictionary = SourceTextModule::Cast(currentModule->GetTaggedObject())->GetNameDictionary();
514 if (dictionary.IsUndefined()) {
515 return false;
516 }
517
518 JSThread *thread = ecmaVm->GetJSThread();
519 JSTaggedValue curValue = JSNApiHelper::ToJSTaggedValue(*value);
520 if (dictionary.IsTaggedArray()) {
521 TaggedArray *array = TaggedArray::Cast(dictionary.GetTaggedObject());
522 array->Set(thread, index, curValue);
523 return true;
524 }
525 return false;
526 }
527
GetModuleValue(const EcmaVM * ecmaVm,const JSHandle<JSTaggedValue> & currentModule,std::string & name)528 Local<JSValueRef> DebuggerApi::GetModuleValue(const EcmaVM *ecmaVm, const JSHandle<JSTaggedValue> ¤tModule,
529 std::string &name)
530 {
531 Local<JSValueRef> result;
532 if (!currentModule->IsSourceTextModule()) {
533 return result;
534 }
535 // Get variable from local export
536 result = GetExportVariableValue(ecmaVm, currentModule, name);
537 if (!result.IsEmpty()) {
538 return result;
539 }
540 // Get variable from import module
541 JSHandle<JSTaggedValue> importModule = GetImportModule(ecmaVm, currentModule, name);
542 result = GetExportVariableValue(ecmaVm, importModule, name);
543 return result;
544 }
545
SetModuleValue(const EcmaVM * ecmaVm,const JSHandle<JSTaggedValue> & currentModule,std::string & name,Local<JSValueRef> value)546 bool DebuggerApi::SetModuleValue(const EcmaVM *ecmaVm, const JSHandle<JSTaggedValue> ¤tModule,
547 std::string &name, Local<JSValueRef> value)
548 {
549 bool result;
550 if (!currentModule->IsSourceTextModule()) {
551 return false;
552 }
553 // Set local export variable
554 result = SetExportVariableValue(ecmaVm, currentModule, name, value);
555 if (result == true) {
556 return result;
557 }
558 // Set import module variable
559 JSHandle<JSTaggedValue> importModule = GetImportModule(ecmaVm, currentModule, name);
560 result = SetExportVariableValue(ecmaVm, importModule, name, value);
561 if (result == true) {
562 return result;
563 }
564 return false;
565 }
566
InitializeExportVariables(const EcmaVM * ecmaVm,Local<ObjectRef> & moduleObj,const JSHandle<JSTaggedValue> & currentModule)567 void DebuggerApi::InitializeExportVariables(const EcmaVM *ecmaVm, Local<ObjectRef> &moduleObj,
568 const JSHandle<JSTaggedValue> ¤tModule)
569 {
570 if (!currentModule->IsSourceTextModule()) {
571 return;
572 }
573 JSTaggedValue localExportEntries = SourceTextModule::Cast(
574 currentModule->GetTaggedObject())->GetLocalExportEntries();
575 if (localExportEntries.IsUndefined()) {
576 return;
577 }
578
579 JSThread *thread = ecmaVm->GetJSThread();
580 JSHandle<TaggedArray> localExportArray(thread, TaggedArray::Cast(localExportEntries.GetTaggedObject()));
581 uint32_t exportEntriesLen = localExportArray->GetLength();
582 JSMutableHandle<LocalExportEntry> ee(thread, thread->GlobalConstants()->GetUndefined());
583 JSMutableHandle<JSTaggedValue> name(thread, thread->GlobalConstants()->GetUndefined());
584 JSMutableHandle<JSTaggedValue> value(thread, thread->GlobalConstants()->GetUndefined());
585 JSTaggedValue moduleValue = JSTaggedValue::Undefined();
586 for (uint32_t idx = 0; idx < exportEntriesLen; idx++) {
587 ee.Update(localExportArray->Get(idx));
588 JSTaggedValue key = ee->GetLocalName();
589 name.Update(key);
590 value.Update(moduleValue);
591 if (key.IsString()) {
592 Local<JSValueRef> variableName = JSNApiHelper::ToLocal<JSValueRef>(name);
593 Local<JSValueRef> variableValue = JSNApiHelper::ToLocal<JSValueRef>(value);
594 PropertyAttribute descriptor(variableValue, true, true, true);
595 moduleObj->DefineProperty(ecmaVm, variableName, descriptor);
596 }
597 }
598 }
599
GetLocalExportVariables(const EcmaVM * ecmaVm,Local<ObjectRef> & moduleObj,const JSHandle<JSTaggedValue> & currentModule,bool isImportStar)600 void DebuggerApi::GetLocalExportVariables(const EcmaVM *ecmaVm, Local<ObjectRef> &moduleObj,
601 const JSHandle<JSTaggedValue> ¤tModule, bool isImportStar)
602 {
603 if (!currentModule->IsSourceTextModule()) {
604 return;
605 }
606 JSTaggedValue dictionary = SourceTextModule::Cast(currentModule->GetTaggedObject())->GetNameDictionary();
607 if (dictionary.IsUndefined()) {
608 InitializeExportVariables(ecmaVm, moduleObj, currentModule);
609 return;
610 }
611
612 JSThread *thread = ecmaVm->GetJSThread();
613 JSMutableHandle<JSTaggedValue> name(thread, thread->GlobalConstants()->GetUndefined());
614 JSMutableHandle<JSTaggedValue> value(thread, thread->GlobalConstants()->GetUndefined());
615 if (dictionary.IsTaggedArray()) {
616 JSTaggedValue localExportEntries = SourceTextModule::Cast(
617 currentModule->GetTaggedObject())->GetLocalExportEntries();
618 ASSERT(localExportEntries.IsTaggedArray());
619 JSHandle<TaggedArray> localExportArray(thread, TaggedArray::Cast(localExportEntries.GetTaggedObject()));
620 uint32_t exportEntriesLen = localExportArray->GetLength();
621 JSHandle<TaggedArray> dict(thread, TaggedArray::Cast(dictionary.GetTaggedObject()));
622 uint32_t valueLen = dict->GetLength();
623 if (exportEntriesLen != valueLen) {
624 LOG_FULL(FATAL) << "Key does not match value";
625 }
626
627 JSMutableHandle<LocalExportEntry> ee(thread, thread->GlobalConstants()->GetUndefined());
628 for (uint32_t idx = 0; idx < exportEntriesLen; idx++) {
629 ee.Update(localExportArray->Get(idx));
630 JSTaggedValue key;
631 if (isImportStar) {
632 key = ee->GetExportName();
633 } else {
634 key = ee->GetLocalName();
635 }
636 name.Update(key);
637 JSTaggedValue moduleValue = dict->Get(idx);
638 if (moduleValue.IsHole()) {
639 moduleValue = JSTaggedValue::Undefined();
640 }
641 value.Update(moduleValue);
642 if (key.IsString()) {
643 Local<JSValueRef> variableName = JSNApiHelper::ToLocal<JSValueRef>(name);
644 Local<JSValueRef> variableValue = JSNApiHelper::ToLocal<JSValueRef>(value);
645 PropertyAttribute descriptor(variableValue, true, true, true);
646 moduleObj->DefineProperty(ecmaVm, variableName, descriptor);
647 }
648 }
649 }
650 }
651
GetIndirectExportVariables(const EcmaVM * ecmaVm,Local<ObjectRef> & moduleObj,const JSHandle<JSTaggedValue> & currentModule)652 void DebuggerApi::GetIndirectExportVariables(const EcmaVM *ecmaVm, Local<ObjectRef> &moduleObj,
653 const JSHandle<JSTaggedValue> ¤tModule)
654 {
655 if (!currentModule->IsSourceTextModule()) {
656 return;
657 }
658 JSTaggedValue indirectExportEntries = SourceTextModule::Cast(
659 currentModule->GetTaggedObject())->GetIndirectExportEntries();
660 if (indirectExportEntries.IsUndefined()) {
661 return;
662 }
663 ASSERT(indirectExportEntries.IsTaggedArray());
664 JSThread *thread = ecmaVm->GetJSThread();
665 JSHandle<TaggedArray> indirectExportArray(thread, TaggedArray::Cast(indirectExportEntries.GetTaggedObject()));
666 uint32_t indirectExportEntriesLen = indirectExportArray->GetLength();
667 JSMutableHandle<IndirectExportEntry> ee(thread, thread->GlobalConstants()->GetUndefined());
668 JSMutableHandle<JSTaggedValue> name(thread, thread->GlobalConstants()->GetUndefined());
669 for (uint32_t idx = 0; idx < indirectExportEntriesLen; idx++) {
670 ee.Update(indirectExportArray->Get(idx));
671 JSTaggedValue key = ee->GetImportName();
672 name.Update(key);
673 if (key.IsString()) {
674 Local<JSValueRef> variableName = JSNApiHelper::ToLocal<JSValueRef>(name);
675 JSHandle<JSTaggedValue> moduleRequest(thread, ee->GetModuleRequest());
676 JSHandle<JSTaggedValue> importModule;
677 JSHandle<SourceTextModule> module = JSHandle<SourceTextModule>::Cast(currentModule);
678 JSTaggedValue moduleRecordName = module->GetEcmaModuleRecordName();
679 if (moduleRecordName.IsUndefined()) {
680 importModule = SourceTextModule::HostResolveImportedModule(thread, module, moduleRequest);
681 } else {
682 importModule = SourceTextModule::HostResolveImportedModuleWithMerge(thread, module, moduleRequest);
683 }
684 std::string importName = EcmaStringAccessor(ee->GetImportName()).ToStdString();
685 Local<JSValueRef> value = GetModuleValue(ecmaVm, importModule, importName);
686 PropertyAttribute descriptor(value, true, true, true);
687 moduleObj->DefineProperty(ecmaVm, variableName, descriptor);
688 }
689 }
690 }
691
GetImportVariables(const EcmaVM * ecmaVm,Local<ObjectRef> & moduleObj,const JSHandle<JSTaggedValue> & currentModule)692 void DebuggerApi::GetImportVariables(const EcmaVM *ecmaVm, Local<ObjectRef> &moduleObj,
693 const JSHandle<JSTaggedValue> ¤tModule)
694 {
695 if (!currentModule->IsSourceTextModule()) {
696 return;
697 }
698 JSTaggedValue importEntries = SourceTextModule::Cast(currentModule->GetTaggedObject())->GetImportEntries();
699 if (importEntries.IsUndefined()) {
700 return;
701 }
702
703 JSThread *thread = ecmaVm->GetJSThread();
704 JSHandle<TaggedArray> importArray(thread, TaggedArray::Cast(importEntries.GetTaggedObject()));
705 uint32_t importEntriesLen = importArray->GetLength();
706 JSHandle<JSTaggedValue> starString = thread->GlobalConstants()->GetHandledStarString();
707 JSMutableHandle<ImportEntry> ee(thread, thread->GlobalConstants()->GetUndefined());
708 JSMutableHandle<JSTaggedValue> name(thread, thread->GlobalConstants()->GetUndefined());
709 for (uint32_t idx = 0; idx < importEntriesLen; idx++) {
710 ee.Update(importArray->Get(idx));
711 JSTaggedValue key = ee->GetImportName();
712 JSTaggedValue localName = ee->GetLocalName();
713 name.Update(localName);
714 if (JSTaggedValue::SameValue(key, starString.GetTaggedValue())) {
715 JSHandle<JSTaggedValue> moduleRequest(thread, ee->GetModuleRequest());
716 JSHandle<JSTaggedValue> importModule;
717 JSHandle<SourceTextModule> module = JSHandle<SourceTextModule>::Cast(currentModule);
718 JSTaggedValue moduleRecordName = module->GetEcmaModuleRecordName();
719 if (moduleRecordName.IsUndefined()) {
720 importModule = SourceTextModule::HostResolveImportedModule(thread, module, moduleRequest);
721 } else {
722 importModule = SourceTextModule::HostResolveImportedModuleWithMerge(thread, module, moduleRequest);
723 }
724 Local<ObjectRef> importModuleObj = ObjectRef::New(ecmaVm);
725 GetLocalExportVariables(ecmaVm, importModuleObj, importModule, true);
726 Local<JSValueRef> variableName = JSNApiHelper::ToLocal<JSValueRef>(name);
727 PropertyAttribute descriptor(static_cast<Local<JSValueRef>>(importModuleObj), true, true, true);
728 moduleObj->DefineProperty(ecmaVm, variableName, descriptor);
729 continue;
730 }
731 JSTaggedValue moduleValue =
732 thread->GetCurrentEcmaContext()->GetModuleManager()->GetModuleValueOutter(idx, currentModule);
733 Local<JSValueRef> value = JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread, moduleValue));
734 Local<JSValueRef> variableName = JSNApiHelper::ToLocal<JSValueRef>(name);
735 PropertyAttribute descriptor(value, true, true, true);
736 moduleObj->DefineProperty(ecmaVm, variableName, descriptor);
737 }
738 }
739
HandleUncaughtException(const EcmaVM * ecmaVm,std::string & message)740 void DebuggerApi::HandleUncaughtException(const EcmaVM *ecmaVm, std::string &message)
741 {
742 JSThread *thread = ecmaVm->GetJSThread();
743 [[maybe_unused]] EcmaHandleScope handleScope(thread);
744 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
745
746 JSHandle<JSTaggedValue> exHandle(thread, thread->GetException());
747 thread->ClearException();
748 if (exHandle->IsJSError()) {
749 JSHandle<JSTaggedValue> nameKey = globalConst->GetHandledNameString();
750 JSHandle<EcmaString> name(JSObject::GetProperty(thread, exHandle, nameKey).GetValue());
751 JSHandle<JSTaggedValue> msgKey = globalConst->GetHandledMessageString();
752 JSHandle<EcmaString> msg(JSObject::GetProperty(thread, exHandle, msgKey).GetValue());
753 message = ConvertToString(*name) + ": " + ConvertToString(*msg);
754 } else {
755 JSHandle<EcmaString> ecmaStr = JSTaggedValue::ToString(thread, exHandle);
756 message = ConvertToString(*ecmaStr);
757 }
758 }
759
GenerateFuncFromBuffer(const EcmaVM * ecmaVm,const void * buffer,size_t size,std::string_view entryPoint)760 Local<FunctionRef> DebuggerApi::GenerateFuncFromBuffer(const EcmaVM *ecmaVm, const void *buffer,
761 size_t size, std::string_view entryPoint)
762 {
763 JSPandaFileManager *mgr = JSPandaFileManager::GetInstance();
764 std::shared_ptr<JSPandaFile> jsPandaFile =
765 mgr->LoadJSPandaFile(ecmaVm->GetJSThread(), "", entryPoint, buffer, size);
766 if (jsPandaFile == nullptr) {
767 return JSValueRef::Undefined(ecmaVm);
768 }
769
770 JSHandle<Program> program = mgr->GenerateProgram(const_cast<EcmaVM *>(ecmaVm), jsPandaFile.get(), entryPoint);
771 JSTaggedValue func = program->GetMainFunction();
772 return JSNApiHelper::ToLocal<FunctionRef>(JSHandle<JSTaggedValue>(ecmaVm->GetJSThread(), func));
773 }
774
EvaluateViaFuncCall(EcmaVM * ecmaVm,Local<FunctionRef> funcRef,std::shared_ptr<FrameHandler> & frameHandler)775 Local<JSValueRef> DebuggerApi::EvaluateViaFuncCall(EcmaVM *ecmaVm, Local<FunctionRef> funcRef,
776 std::shared_ptr<FrameHandler> &frameHandler)
777 {
778 JSNApi::EnableUserUncaughtErrorHandler(ecmaVm);
779
780 JsDebuggerManager *mgr = ecmaVm->GetJsDebuggerManager();
781 bool prevDebugMode = mgr->IsDebugMode();
782 mgr->SetEvalFrameHandler(frameHandler);
783 mgr->SetDebugMode(false); // in order to catch exception
784 ecmaVm->GetJSThread()->CheckSwitchDebuggerBCStub();
785 std::vector<Local<JSValueRef>> args;
786 auto result = funcRef->Call(ecmaVm, JSValueRef::Undefined(ecmaVm), args.data(), args.size());
787 mgr->SetDebugMode(prevDebugMode);
788 ecmaVm->GetJSThread()->CheckSwitchDebuggerBCStub();
789 mgr->SetEvalFrameHandler(nullptr);
790
791 return result;
792 }
793
IsExceptionCaught(const EcmaVM * ecmaVm)794 bool DebuggerApi::IsExceptionCaught(const EcmaVM *ecmaVm)
795 {
796 FrameHandler frameHandler(ecmaVm->GetJSThread());
797 for (; frameHandler.HasFrame(); frameHandler.PrevJSFrame()) {
798 if (frameHandler.IsEntryFrame()) {
799 return false;
800 }
801 auto method = frameHandler.GetMethod();
802 if (method->FindCatchBlock(frameHandler.GetBytecodeOffset() != INVALID_INDEX)) {
803 return true;
804 }
805 }
806 return false;
807 }
808
GetPatchExtractor(const EcmaVM * ecmaVm,const std::string & url)809 DebugInfoExtractor *DebuggerApi::GetPatchExtractor(const EcmaVM *ecmaVm, const std::string &url)
810 {
811 const auto *hotReloadManager = ecmaVm->GetJsDebuggerManager()->GetHotReloadManager();
812 return hotReloadManager->GetPatchExtractor(url);
813 }
814
GetBaseJSPandaFile(const EcmaVM * ecmaVm,const JSPandaFile * jsPandaFile)815 const JSPandaFile *DebuggerApi::GetBaseJSPandaFile(const EcmaVM *ecmaVm, const JSPandaFile *jsPandaFile)
816 {
817 const auto *hotReloadManager = ecmaVm->GetJsDebuggerManager()->GetHotReloadManager();
818 return hotReloadManager->GetBaseJSPandaFile(jsPandaFile);
819 }
820
GetNativePointer(const EcmaVM * ecmaVm)821 std::vector<void *> DebuggerApi::GetNativePointer(const EcmaVM *ecmaVm)
822 {
823 void *native = nullptr;
824 std::vector<void *> nativePointer;
825 JSThread *thread = ecmaVm->GetJSThread();
826 JSTaggedType *current = const_cast<JSTaggedType *>(thread->GetCurrentFrame());
827 FrameIterator it(current, thread);
828 for (; !it.Done(); it.Advance<GCVisitedFlag::HYBRID_STACK>()) {
829 if (!it.IsJSFrame()) {
830 continue;
831 }
832 auto method = it.CheckAndGetMethod();
833 if (method == nullptr) {
834 continue;
835 }
836
837 if (method->IsNativeWithCallField()) {
838 JSTaggedValue function = it.GetFunction();
839 JSHandle<JSTaggedValue> extraInfoValue(
840 thread, JSFunction::Cast(function.GetTaggedObject())->GetFunctionExtraInfo());
841 auto cb = ecmaVm->GetNativePtrGetter();
842 if (extraInfoValue->IsJSNativePointer() && cb != nullptr) {
843 JSHandle<JSNativePointer> extraInfo(extraInfoValue);
844 native = cb(reinterpret_cast<void *>(extraInfo->GetData()));
845 nativePointer.push_back(native);
846 }
847 } else {
848 nativePointer.push_back(nullptr); // to tell IDE this frame don't hava nativePointer
849 }
850 }
851 return nativePointer;
852 }
853
GetContainerLength(const EcmaVM * ecmaVm,Local<JSValueRef> value)854 uint32_t DebuggerApi::GetContainerLength(const EcmaVM *ecmaVm, Local<JSValueRef> value)
855 {
856 uint32_t length = Local<ArrayRef>(value)->Length(ecmaVm);
857 return length;
858 }
859
AddInternalProperties(const EcmaVM * ecmaVm,Local<ObjectRef> object,ArkInternalValueType type,Global<MapRef> internalObjects)860 void DebuggerApi::AddInternalProperties(const EcmaVM *ecmaVm, Local<ObjectRef> object,
861 ArkInternalValueType type, Global<MapRef> internalObjects)
862 {
863 internalObjects->Set(ecmaVm, object, NumberRef::New(ecmaVm, static_cast<int32_t>(type)));
864 }
865
GetArrayListValue(const EcmaVM * ecmaVm,Local<JSValueRef> value,Global<MapRef> internalObjects)866 Local<JSValueRef> DebuggerApi::GetArrayListValue(const EcmaVM *ecmaVm, Local<JSValueRef> value,
867 Global<MapRef> internalObjects)
868 {
869 JSHandle<JSAPIArrayList> arrayList(JSNApiHelper::ToJSHandle(value));
870 uint32_t size = static_cast<uint32_t>(arrayList->GetSize());
871 Local<JSValueRef> jsValueRef = ArrayRef::New(ecmaVm, size);
872 JSThread *thread = ecmaVm->GetJSThread();
873 JSMutableHandle<JSTaggedValue> currentValue(thread, JSTaggedValue::Undefined());
874 uint32_t index = 0;
875 while (index < size) {
876 currentValue.Update(arrayList->Get(thread, index));
877 ArrayRef::SetValueAt(ecmaVm, jsValueRef, index++, JSNApiHelper::ToLocal<JSValueRef>(currentValue));
878 }
879 AddInternalProperties(ecmaVm, jsValueRef, ArkInternalValueType::Entry, internalObjects);
880 return jsValueRef;
881 }
882
GetDequeValue(const EcmaVM * ecmaVm,Local<JSValueRef> value,Global<MapRef> internalObjects)883 Local<JSValueRef> DebuggerApi::GetDequeValue(const EcmaVM *ecmaVm, Local<JSValueRef> value,
884 Global<MapRef> internalObjects)
885 {
886 JSHandle<JSAPIDeque> deque(JSNApiHelper::ToJSHandle(value));
887 uint32_t size = static_cast<uint32_t>(deque->GetSize());
888 Local<JSValueRef> jsValueRef = ArrayRef::New(ecmaVm, size);
889 JSThread *thread = ecmaVm->GetJSThread();
890 JSMutableHandle<JSTaggedValue> currentValue(thread, JSTaggedValue::Undefined());
891 uint32_t index = 0;
892 while (index < size) {
893 currentValue.Update(deque->Get(index));
894 ArrayRef::SetValueAt(ecmaVm, jsValueRef, index++, JSNApiHelper::ToLocal<JSValueRef>(currentValue));
895 }
896 AddInternalProperties(ecmaVm, jsValueRef, ArkInternalValueType::Entry, internalObjects);
897 return jsValueRef;
898 }
899
GetHashMapValue(const EcmaVM * ecmaVm,Local<JSValueRef> value,Global<MapRef> internalObjects)900 Local<JSValueRef> DebuggerApi::GetHashMapValue(const EcmaVM *ecmaVm, Local<JSValueRef> value,
901 Global<MapRef> internalObjects)
902 {
903 JSHandle<JSAPIHashMap> hashMap(JSNApiHelper::ToJSHandle(value));
904 JSThread *thread = ecmaVm->GetJSThread();
905 JSHandle<TaggedHashArray> table(thread, hashMap->GetTable());
906 uint32_t length = table->GetLength();
907 uint32_t size = static_cast<uint32_t>(hashMap->GetSize());
908 Local<JSValueRef> jsValueRef = ArrayRef::New(ecmaVm, size);
909 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
910 JSMutableHandle<TaggedQueue> queue(thread, factory->NewTaggedQueue(0));
911 JSMutableHandle<TaggedNode> node(thread, JSTaggedValue::Undefined());
912 JSMutableHandle<JSTaggedValue> currentKey(thread, JSTaggedValue::Undefined());
913 JSMutableHandle<JSTaggedValue> currentValue(thread, JSTaggedValue::Undefined());
914 Local<JSValueRef> jsKey = StringRef::NewFromUtf8(ecmaVm, "key");
915 Local<JSValueRef> jsValue = StringRef::NewFromUtf8(ecmaVm, "value");
916 uint32_t pos = 0;
917 uint32_t index = 0;
918 while (index < length) {
919 node.Update(TaggedHashArray::GetCurrentNode(thread, queue, table, index));
920 if (!node.GetTaggedValue().IsHole()) {
921 currentKey.Update(node->GetKey());
922 currentValue.Update(node->GetValue());
923 Local<ObjectRef> objRef = ObjectRef::New(ecmaVm);
924 objRef->Set(ecmaVm, jsKey, JSNApiHelper::ToLocal<JSValueRef>(currentKey));
925 objRef->Set(ecmaVm, jsValue, JSNApiHelper::ToLocal<JSValueRef>(currentValue));
926 AddInternalProperties(ecmaVm, objRef, ArkInternalValueType::Entry, internalObjects);
927 ArrayRef::SetValueAt(ecmaVm, jsValueRef, pos++, objRef);
928 }
929 }
930 AddInternalProperties(ecmaVm, jsValueRef, ArkInternalValueType::Entry, internalObjects);
931 return jsValueRef;
932 }
933
GetHashSetValue(const EcmaVM * ecmaVm,Local<JSValueRef> value,Global<MapRef> internalObjects)934 Local<JSValueRef> DebuggerApi::GetHashSetValue(const EcmaVM *ecmaVm, Local<JSValueRef> value,
935 Global<MapRef> internalObjects)
936 {
937 JSHandle<JSAPIHashSet> hashSet(JSNApiHelper::ToJSHandle(value));
938 JSThread *thread = ecmaVm->GetJSThread();
939 JSHandle<TaggedHashArray> table(thread, hashSet->GetTable());
940 uint32_t length = table->GetLength();
941 uint32_t size = static_cast<uint32_t>(hashSet->GetSize());
942 Local<JSValueRef> jsValueRef = ArrayRef::New(ecmaVm, size);
943 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
944 JSMutableHandle<TaggedQueue> queue(thread, factory->NewTaggedQueue(0));
945 JSMutableHandle<TaggedNode> node(thread, JSTaggedValue::Undefined());
946 JSMutableHandle<JSTaggedValue> currentKey(thread, JSTaggedValue::Undefined());
947 Local<JSValueRef> jsValue = StringRef::NewFromUtf8(ecmaVm, "value");
948 uint32_t pos = 0;
949 uint32_t index = 0;
950 while (index < length) {
951 node.Update(TaggedHashArray::GetCurrentNode(thread, queue, table, index));
952 if (!node.GetTaggedValue().IsHole()) {
953 currentKey.Update(node->GetKey());
954 if (currentKey->IsECMAObject()) {
955 Local<ObjectRef> objRef = ObjectRef::New(ecmaVm);
956 objRef->Set(ecmaVm, jsValue, JSNApiHelper::ToLocal<JSValueRef>(currentKey));
957 AddInternalProperties(ecmaVm, objRef, ArkInternalValueType::Entry, internalObjects);
958 ArrayRef::SetValueAt(ecmaVm, jsValueRef, pos++, objRef);
959 } else {
960 ArrayRef::SetValueAt(ecmaVm, jsValueRef, pos++, JSNApiHelper::ToLocal<JSValueRef>(currentKey));
961 }
962 }
963 }
964 AddInternalProperties(ecmaVm, jsValueRef, ArkInternalValueType::Entry, internalObjects);
965 return jsValueRef;
966 }
967
GetLightWeightMapValue(const EcmaVM * ecmaVm,Local<JSValueRef> value,Global<MapRef> internalObjects)968 Local<JSValueRef> DebuggerApi::GetLightWeightMapValue(const EcmaVM *ecmaVm, Local<JSValueRef> value,
969 Global<MapRef> internalObjects)
970 {
971 JSHandle<JSAPILightWeightMap> lightweightMap(JSNApiHelper::ToJSHandle(value));
972 uint32_t size = static_cast<uint32_t>(lightweightMap->GetSize());
973 Local<JSValueRef> jsValueRef = ArrayRef::New(ecmaVm, size);
974 JSThread *thread = ecmaVm->GetJSThread();
975 JSMutableHandle<TaggedArray> keys(thread, lightweightMap->GetKeys());
976 JSMutableHandle<TaggedArray> values(thread, lightweightMap->GetValues());
977 JSMutableHandle<JSTaggedValue> currentKey(thread, JSTaggedValue::Undefined());
978 JSMutableHandle<JSTaggedValue> currentValue(thread, JSTaggedValue::Undefined());
979 Local<JSValueRef> jsKey = StringRef::NewFromUtf8(ecmaVm, "key");
980 Local<JSValueRef> jsValue = StringRef::NewFromUtf8(ecmaVm, "value");
981 uint32_t index = 0;
982 while (index < size) {
983 currentKey.Update(keys->Get(index));
984 currentValue.Update(values->Get(index));
985 Local<ObjectRef> objRef = ObjectRef::New(ecmaVm);
986 objRef->Set(ecmaVm, jsKey, JSNApiHelper::ToLocal<JSValueRef>(currentKey));
987 objRef->Set(ecmaVm, jsValue, JSNApiHelper::ToLocal<JSValueRef>(currentValue));
988 AddInternalProperties(ecmaVm, objRef, ArkInternalValueType::Entry, internalObjects);
989 ArrayRef::SetValueAt(ecmaVm, jsValueRef, index++, objRef);
990 }
991 AddInternalProperties(ecmaVm, jsValueRef, ArkInternalValueType::Entry, internalObjects);
992 return jsValueRef;
993 }
994
GetLightWeightSetValue(const EcmaVM * ecmaVm,Local<JSValueRef> value,Global<MapRef> internalObjects)995 Local<JSValueRef> DebuggerApi::GetLightWeightSetValue(const EcmaVM *ecmaVm, Local<JSValueRef> value,
996 Global<MapRef> internalObjects)
997 {
998 JSHandle<JSAPILightWeightSet> lightWeightSet(JSNApiHelper::ToJSHandle(value));
999 uint32_t size = static_cast<uint32_t>(lightWeightSet->GetSize());
1000 Local<JSValueRef> jsValueRef = ArrayRef::New(ecmaVm, size);
1001 JSThread *thread = ecmaVm->GetJSThread();
1002 JSMutableHandle<JSTaggedValue> currentValue(thread, JSTaggedValue::Undefined());
1003 Local<JSValueRef> jsValue = StringRef::NewFromUtf8(ecmaVm, "value");
1004 uint32_t index = 0;
1005 while (index < size) {
1006 currentValue.Update(lightWeightSet->GetValueAt(index));
1007 if (currentValue->IsECMAObject()) {
1008 Local<ObjectRef> objRef = ObjectRef::New(ecmaVm);
1009 objRef->Set(ecmaVm, jsValue, JSNApiHelper::ToLocal<JSValueRef>(currentValue));
1010 AddInternalProperties(ecmaVm, objRef, ArkInternalValueType::Entry, internalObjects);
1011 ArrayRef::SetValueAt(ecmaVm, jsValueRef, index++, objRef);
1012 } else {
1013 ArrayRef::SetValueAt(ecmaVm, jsValueRef, index++, JSNApiHelper::ToLocal<JSValueRef>(currentValue));
1014 }
1015 }
1016 AddInternalProperties(ecmaVm, jsValueRef, ArkInternalValueType::Entry, internalObjects);
1017 return jsValueRef;
1018 }
1019
GetLinkedListValue(const EcmaVM * ecmaVm,Local<JSValueRef> value,Global<MapRef> internalObjects)1020 Local<JSValueRef> DebuggerApi::GetLinkedListValue(const EcmaVM *ecmaVm, Local<JSValueRef> value,
1021 Global<MapRef> internalObjects)
1022 {
1023 JSHandle<JSAPILinkedList> linkedList(JSNApiHelper::ToJSHandle(value));
1024 JSThread *thread = ecmaVm->GetJSThread();
1025 JSHandle<TaggedDoubleList> doubleList(thread, linkedList->GetDoubleList());
1026 uint32_t size = static_cast<uint32_t>(linkedList->Length());
1027 Local<JSValueRef> jsValueRef = ArrayRef::New(ecmaVm, size);
1028 JSMutableHandle<JSTaggedValue> currentValue(thread, JSTaggedValue::Undefined());
1029 int valueNode = TaggedDoubleList::ELEMENTS_START_INDEX;
1030 uint32_t index = 0;
1031 while (index < size) {
1032 valueNode = doubleList->GetNextDataIndex(valueNode);
1033 currentValue.Update(doubleList->GetElement(valueNode));
1034 ArrayRef::SetValueAt(ecmaVm, jsValueRef, index++, JSNApiHelper::ToLocal<JSValueRef>(currentValue));
1035 }
1036 AddInternalProperties(ecmaVm, jsValueRef, ArkInternalValueType::Entry, internalObjects);
1037 return jsValueRef;
1038 }
1039
GetListValue(const EcmaVM * ecmaVm,Local<JSValueRef> value,Global<MapRef> internalObjects)1040 Local<JSValueRef> DebuggerApi::GetListValue(const EcmaVM *ecmaVm, Local<JSValueRef> value,
1041 Global<MapRef> internalObjects)
1042 {
1043 JSHandle<JSAPIList> list(JSNApiHelper::ToJSHandle(value));
1044 JSThread *thread = ecmaVm->GetJSThread();
1045 JSHandle<TaggedSingleList> singleList(thread, list->GetSingleList());
1046 uint32_t size = static_cast<uint32_t>(list->Length());
1047 Local<JSValueRef> jsValueRef = ArrayRef::New(ecmaVm, size);
1048 JSMutableHandle<JSTaggedValue> currentValue(thread, JSTaggedValue::Undefined());
1049 int valueNode = TaggedDoubleList::ELEMENTS_START_INDEX;
1050 uint32_t index = 0;
1051 while (index < size) {
1052 valueNode = singleList->GetNextDataIndex(valueNode);
1053 currentValue.Update(singleList->GetElement(valueNode));
1054 ArrayRef::SetValueAt(ecmaVm, jsValueRef, index++, JSNApiHelper::ToLocal<JSValueRef>(currentValue));
1055 }
1056 AddInternalProperties(ecmaVm, jsValueRef, ArkInternalValueType::Entry, internalObjects);
1057 return jsValueRef;
1058 }
1059
GetPlainArrayValue(const EcmaVM * ecmaVm,Local<JSValueRef> value,Global<MapRef> internalObjects)1060 Local<JSValueRef> DebuggerApi::GetPlainArrayValue(const EcmaVM *ecmaVm, Local<JSValueRef> value,
1061 Global<MapRef> internalObjects)
1062 {
1063 JSHandle<JSAPIPlainArray> plainarray(JSNApiHelper::ToJSHandle(value));
1064 uint32_t size = static_cast<uint32_t>(plainarray->GetSize());
1065 Local<JSValueRef> jsValueRef = ArrayRef::New(ecmaVm, size);
1066 JSThread *thread = ecmaVm->GetJSThread();
1067 JSHandle<TaggedArray> keyArray(thread, plainarray->GetKeys());
1068 JSHandle<TaggedArray> valueArray(thread, plainarray->GetValues());
1069 JSMutableHandle<JSTaggedValue> currentKey(thread, JSTaggedValue::Undefined());
1070 JSMutableHandle<JSTaggedValue> currentValue(thread, JSTaggedValue::Undefined());
1071 Local<JSValueRef> jsKey = StringRef::NewFromUtf8(ecmaVm, "key");
1072 Local<JSValueRef> jsValue = StringRef::NewFromUtf8(ecmaVm, "value");
1073 uint32_t index = 0;
1074 while (index < size) {
1075 currentKey.Update(keyArray->Get(index));
1076 currentValue.Update(valueArray->Get(index));
1077 Local<ObjectRef> objRef = ObjectRef::New(ecmaVm);
1078 objRef->Set(ecmaVm, jsKey, JSNApiHelper::ToLocal<JSValueRef>(currentKey));
1079 objRef->Set(ecmaVm, jsValue, JSNApiHelper::ToLocal<JSValueRef>(currentValue));
1080 AddInternalProperties(ecmaVm, objRef, ArkInternalValueType::Entry, internalObjects);
1081 ArrayRef::SetValueAt(ecmaVm, jsValueRef, index++, objRef);
1082 }
1083 AddInternalProperties(ecmaVm, jsValueRef, ArkInternalValueType::Entry, internalObjects);
1084 return jsValueRef;
1085 }
1086
GetQueueValue(const EcmaVM * ecmaVm,Local<JSValueRef> value,Global<MapRef> internalObjects)1087 Local<JSValueRef> DebuggerApi::GetQueueValue(const EcmaVM *ecmaVm, Local<JSValueRef> value,
1088 Global<MapRef> internalObjects)
1089 {
1090 JSHandle<JSAPIQueue> queue(JSNApiHelper::ToJSHandle(value));
1091 uint32_t size = static_cast<uint32_t>(queue->GetSize());
1092 Local<JSValueRef> jsValueRef = ArrayRef::New(ecmaVm, size);
1093 JSThread *thread = ecmaVm->GetJSThread();
1094 JSMutableHandle<JSTaggedValue> currentValue(thread, JSTaggedValue::Undefined());
1095 uint32_t pos = 0;
1096 uint32_t index = 0;
1097 while (index < size) {
1098 currentValue.Update(queue->Get(thread, pos));
1099 pos = queue->GetNextPosition(pos);
1100 ArrayRef::SetValueAt(ecmaVm, jsValueRef, index++, JSNApiHelper::ToLocal<JSValueRef>(currentValue));
1101 }
1102 AddInternalProperties(ecmaVm, jsValueRef, ArkInternalValueType::Entry, internalObjects);
1103 return jsValueRef;
1104 }
1105
GetStackValue(const EcmaVM * ecmaVm,Local<JSValueRef> value,Global<MapRef> internalObjects)1106 Local<JSValueRef> DebuggerApi::GetStackValue(const EcmaVM *ecmaVm, Local<JSValueRef> value,
1107 Global<MapRef> internalObjects)
1108 {
1109 JSHandle<JSAPIStack> stack(JSNApiHelper::ToJSHandle(value));
1110 uint32_t size = static_cast<uint32_t>(stack->GetSize());
1111 Local<JSValueRef> jsValueRef = ArrayRef::New(ecmaVm, size);
1112 JSThread *thread = ecmaVm->GetJSThread();
1113 JSMutableHandle<JSTaggedValue> currentValue(thread, JSTaggedValue::Undefined());
1114 uint32_t index = 0;
1115 while (index < size + 1) {
1116 currentValue.Update(stack->Get(index));
1117 ArrayRef::SetValueAt(ecmaVm, jsValueRef, index++, JSNApiHelper::ToLocal<JSValueRef>(currentValue));
1118 }
1119 AddInternalProperties(ecmaVm, jsValueRef, ArkInternalValueType::Entry, internalObjects);
1120 return jsValueRef;
1121 }
1122
GetTreeMapValue(const EcmaVM * ecmaVm,Local<JSValueRef> value,Global<MapRef> internalObjects)1123 Local<JSValueRef> DebuggerApi::GetTreeMapValue(const EcmaVM *ecmaVm, Local<JSValueRef> value,
1124 Global<MapRef> internalObjects)
1125 {
1126 JSHandle<JSAPITreeMap> treeMap(JSNApiHelper::ToJSHandle(value));
1127 uint32_t size = static_cast<uint32_t>(treeMap->GetSize());
1128 Local<JSValueRef> jsValueRef = ArrayRef::New(ecmaVm, size);
1129 JSThread *thread = ecmaVm->GetJSThread();
1130 JSMutableHandle<TaggedTreeMap> iteratedMap(thread, treeMap->GetTreeMap());
1131 uint32_t elements = static_cast<uint32_t>(iteratedMap->NumberOfElements());
1132 JSHandle<TaggedArray> entries = TaggedTreeMap::GetArrayFromMap(thread, iteratedMap);
1133 JSMutableHandle<JSTaggedValue> currentKey(thread, JSTaggedValue::Undefined());
1134 JSMutableHandle<JSTaggedValue> currentValue(thread, JSTaggedValue::Undefined());
1135 Local<JSValueRef> jsKey = StringRef::NewFromUtf8(ecmaVm, "key");
1136 Local<JSValueRef> jsValue = StringRef::NewFromUtf8(ecmaVm, "value");
1137 uint32_t index = 0;
1138 while (index < elements) {
1139 int entriesIndex = entries->Get(index).GetInt();
1140 currentKey.Update(iteratedMap->GetKey(entriesIndex));
1141 currentValue.Update(iteratedMap->GetValue(entriesIndex));
1142 Local<ObjectRef> objRef = ObjectRef::New(ecmaVm);
1143 objRef->Set(ecmaVm, jsKey, JSNApiHelper::ToLocal<JSValueRef>(currentKey));
1144 objRef->Set(ecmaVm, jsValue, JSNApiHelper::ToLocal<JSValueRef>(currentValue));
1145 AddInternalProperties(ecmaVm, objRef, ArkInternalValueType::Entry, internalObjects);
1146 ArrayRef::SetValueAt(ecmaVm, jsValueRef, index++, objRef);
1147 }
1148 AddInternalProperties(ecmaVm, jsValueRef, ArkInternalValueType::Entry, internalObjects);
1149 return jsValueRef;
1150 }
1151
GetTreeSetValue(const EcmaVM * ecmaVm,Local<JSValueRef> value,Global<MapRef> internalObjects)1152 Local<JSValueRef> DebuggerApi::GetTreeSetValue(const EcmaVM *ecmaVm, Local<JSValueRef> value,
1153 Global<MapRef> internalObjects)
1154 {
1155 JSHandle<JSAPITreeSet> treeSet(JSNApiHelper::ToJSHandle(value));
1156 JSThread *thread = ecmaVm->GetJSThread();
1157 JSMutableHandle<TaggedTreeSet> iteratedSet(thread, treeSet->GetTreeSet());
1158 uint32_t elements = static_cast<uint32_t>(iteratedSet->NumberOfElements());
1159 Local<JSValueRef> jsValueRef = ArrayRef::New(ecmaVm, elements);
1160 JSHandle<TaggedArray> entries = TaggedTreeSet::GetArrayFromSet(thread, iteratedSet);
1161 JSMutableHandle<JSTaggedValue> currentValue(thread, JSTaggedValue::Undefined());
1162 Local<JSValueRef> jsValue = StringRef::NewFromUtf8(ecmaVm, "value");
1163 uint32_t index = 0;
1164 while (index < elements) {
1165 int entriesIndex = entries->Get(index).GetInt();
1166 currentValue.Update(iteratedSet->GetKey(entriesIndex));
1167 if (currentValue->IsECMAObject()) {
1168 Local<ObjectRef> objRef = ObjectRef::New(ecmaVm);
1169 objRef->Set(ecmaVm, jsValue, JSNApiHelper::ToLocal<JSValueRef>(currentValue));
1170 AddInternalProperties(ecmaVm, objRef, ArkInternalValueType::Entry, internalObjects);
1171 ArrayRef::SetValueAt(ecmaVm, jsValueRef, index++, objRef);
1172 } else {
1173 ArrayRef::SetValueAt(ecmaVm, jsValueRef, index++, JSNApiHelper::ToLocal<JSValueRef>(currentValue));
1174 }
1175 }
1176 AddInternalProperties(ecmaVm, jsValueRef, ArkInternalValueType::Entry, internalObjects);
1177 return jsValueRef;
1178 }
1179
GetVectorValue(const EcmaVM * ecmaVm,Local<JSValueRef> value,Global<MapRef> internalObjects)1180 Local<JSValueRef> DebuggerApi::GetVectorValue(const EcmaVM *ecmaVm, Local<JSValueRef> value,
1181 Global<MapRef> internalObjects)
1182 {
1183 JSHandle<JSAPIVector> vector(JSNApiHelper::ToJSHandle(value));
1184 uint32_t size = static_cast<uint32_t>(vector->GetSize());
1185 Local<JSValueRef> jsValueRef = ArrayRef::New(ecmaVm, size);
1186 JSThread *thread = ecmaVm->GetJSThread();
1187 JSMutableHandle<JSTaggedValue> currentValue(thread, JSTaggedValue::Undefined());
1188 uint32_t index = 0;
1189 while (index < size) {
1190 currentValue.Update(vector->Get(thread, vector, index));
1191 ArrayRef::SetValueAt(ecmaVm, jsValueRef, index++, JSNApiHelper::ToLocal<JSValueRef>(currentValue));
1192 }
1193 AddInternalProperties(ecmaVm, jsValueRef, ArkInternalValueType::Entry, internalObjects);
1194 return jsValueRef;
1195 }
1196
DropLastFrame(const EcmaVM * ecmaVm)1197 void DebuggerApi::DropLastFrame(const EcmaVM *ecmaVm)
1198 {
1199 JSThread *thread = ecmaVm->GetJSThread();
1200 auto *debuggerMgr = ecmaVm->GetJsDebuggerManager();
1201 if (!thread->IsAsmInterpreter()) {
1202 debuggerMgr->DropLastFrame();
1203 }
1204 }
1205 } // namespace panda::ecmascript::tooling
1206