• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "ecmascript/napi/include/dfx_jsnapi.h"
17 
18 #include "ecmascript/base/block_hook_scope.h"
19 #include "ecmascript/base/config.h"
20 #include "ecmascript/builtins/builtins_ark_tools.h"
21 #include "ecmascript/checkpoint/thread_state_transition.h"
22 #include "common_components/mutator/mutator_manager.h"
23 #include "ecmascript/debugger/debugger_api.h"
24 #include "ecmascript/debugger/js_debugger_manager.h"
25 #include "ecmascript/dfx/hprof/heap_profiler.h"
26 #include "ecmascript/dfx/stackinfo/async_stack_trace.h"
27 #include "ecmascript/dfx/stackinfo/js_stackinfo.h"
28 #include "ecmascript/dfx/tracing/tracing.h"
29 #include "ecmascript/dfx/vm_thread_control.h"
30 #include "ecmascript/jit/jit.h"
31 #include "ecmascript/jspandafile/js_pandafile_executor.h"
32 #include "ecmascript/mem/heap-inl.h"
33 #include "ecmascript/ohos/ohos_constants.h"
34 
35 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
36 #include "ecmascript/dfx/cpu_profiler/cpu_profiler.h"
37 #include "ecmascript/dfx/cpu_profiler/samples_record.h"
38 #endif
39 #if defined(ENABLE_DUMP_IN_FAULTLOG)
40 #include "faultloggerd_client.h"
41 #include "uv.h"
42 #endif
43 
44 namespace panda {
45 using ecmascript::CString;
46 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
47 using BuiltinsArkTools = ecmascript::builtins::BuiltinsArkTools;
48 using ecmascript::CpuProfiler;
49 #endif
50 using ecmascript::EcmaString;
51 using ecmascript::JSTaggedValue;
52 using ecmascript::GCStats;
53 template<typename T>
54 using JSHandle = ecmascript::JSHandle<T>;
55 using ecmascript::FileStream;
56 using ecmascript::FileDescriptorStream;
57 using ecmascript::CMap;
58 using ecmascript::Tracing;
59 using ecmascript::DumpSnapShotOption;
60 using ecmascript::g_isEnableCMCGC;
61 using ecmascript::JSFunction;
62 using ecmascript::JSPandaFileExecutor;
63 using ecmascript::SourceTextModule;
64 
65 sem_t g_heapdumpCnt;
66 
DumpHeapSnapshot(const EcmaVM * vm,const std::string & path,const DumpSnapShotOption & dumpOption,const std::function<void (uint8_t)> & callback)67 void DFXJSNApi::DumpHeapSnapshot([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] const std::string &path,
68                                  [[maybe_unused]] const DumpSnapShotOption &dumpOption,
69                                  const std::function<void(uint8_t)> &callback)
70 {
71 #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT)
72     FileStream stream(path);
73     DumpHeapSnapshot(vm, &stream, dumpOption, nullptr, callback);
74 #else
75     if (callback) {
76         callback(static_cast<uint8_t>(ecmascript::DumpHeapSnapshotStatus::FORK_FAILED));
77     }
78     LOG_ECMA(ERROR) << "Not support arkcompiler heap snapshot";
79 #endif
80 }
81 
82 // IDE interface.
DumpHeapSnapshot(const EcmaVM * vm,Stream * stream,const DumpSnapShotOption & dumpOption,Progress * progress,std::function<void (uint8_t)> callback)83 void DFXJSNApi::DumpHeapSnapshot([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] Stream *stream,
84                                  [[maybe_unused]] const DumpSnapShotOption &dumpOption,
85                                  [[maybe_unused]] Progress *progress,
86                                  [[maybe_unused]] std::function<void(uint8_t)> callback)
87 {
88 #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT)
89     ecmascript::HeapProfilerInterface *heapProfile = ecmascript::HeapProfilerInterface::GetInstance(
90         const_cast<EcmaVM *>(vm));
91 
92 #if defined (ENABLE_LOCAL_HANDLE_LEAK_DETECT)
93 #if defined (ENABLE_DUMP_IN_FAULTLOG)
94     auto heapProfiler = reinterpret_cast<ecmascript::HeapProfiler *>(heapProfile);
95     heapProfiler->SwitchStartLocalHandleLeakDetect();
96     if (heapProfiler->IsStartLocalHandleLeakDetect()) {
97         int32_t fd = RequestFileDescriptor(static_cast<int32_t>(FaultLoggerType::JS_STACKTRACE));
98         if (fd < 0) {
99             LOG_ECMA(ERROR) << "[LocalHandleLeakDetect] Failed on request file descriptor";
100         } else {
101             heapProfiler->SetLeakStackTraceFd(fd);
102         }
103     }
104 #endif  // ENABLE_DUMP_IN_FAULTLOG
105 #endif  // ENABLE_LOCAL_HANDLE_LEAK_DETECT
106     heapProfile->DumpHeapSnapshot(stream, dumpOption, progress, callback);
107 #else
108     LOG_ECMA(ERROR) << "Not support arkcompiler heap snapshot";
109 #endif
110 }
111 
112 [[maybe_unused]] static uint8_t killCount = 0;
113 
DumpCpuProfile(const EcmaVM * vm)114 void DFXJSNApi::DumpCpuProfile([[maybe_unused]] const EcmaVM *vm)
115 {
116 #if ECMASCRIPT_ENABLE_MEGA_PROFILER
117     vm->GetJSThread()->PrintMegaICStat();
118 #endif
119 #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT)
120 #if defined(ENABLE_DUMP_IN_FAULTLOG)
121 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
122     // for CpuProfiler kill contral
123     if (DFXJSNApi::StopCpuProfilerForColdStart(vm)) {
124         return;
125     }
126 
127     (void)killCount;
128     if (DFXJSNApi::CpuProfilerSamplingAnyTime(vm)) {
129         killCount++;
130         return;
131     }
132 #endif // ECMASCRIPT_SUPPORT_CPUPROFILER
133 #endif // ENABLE_DUMP_IN_FAULTLOG
134 #endif // ECMASCRIPT_SUPPORT_SNAPSHOT
135 }
136 
137 // kill -39.
DumpHeapSnapshot(const EcmaVM * vm,const DumpSnapShotOption & dumpOption)138 void DFXJSNApi::DumpHeapSnapshot([[maybe_unused]] const EcmaVM *vm,
139                                  [[maybe_unused]] const DumpSnapShotOption &dumpOption)
140 {
141 #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT)
142 #if defined(ENABLE_DUMP_IN_FAULTLOG)
143     sem_wait(&g_heapdumpCnt);
144     auto &options = const_cast<EcmaVM *>(vm)->GetJSOptions();
145     options.SwitchStartGlobalLeakCheck();
146     if (options.EnableGlobalLeakCheck() && options.IsStartGlobalLeakCheck()) {
147         int32_t stackTraceFd = RequestFileDescriptor(static_cast<int32_t>(FaultLoggerType::JS_STACKTRACE));
148         if (stackTraceFd < 0) {
149             options.SwitchStartGlobalLeakCheck();
150         } else {
151             vm->GetJSThread()->SetStackTraceFd(stackTraceFd);
152         }
153     }
154 
155     // Write in faultlog for heap leak.
156     int32_t fd;
157     if (dumpOption.isDumpOOM && dumpOption.dumpFormat == DumpFormat::BINARY) {
158         fd = RequestFileDescriptor(static_cast<int32_t>(FaultLoggerType::JS_RAW_SNAPSHOT));
159     } else {
160         fd = RequestFileDescriptor(static_cast<int32_t>(FaultLoggerType::JS_HEAP_SNAPSHOT));
161     }
162     if (fd < 0) {
163         LOG_ECMA(ERROR) << "Write FD failed, fd" << fd;
164         return;
165     }
166     FileDescriptorStream stream(fd);
167     ecmascript::HeapProfilerInterface *heapProfile = ecmascript::HeapProfilerInterface::GetInstance(
168         const_cast<EcmaVM *>(vm));
169     heapProfile->DumpHeapSnapshot(&stream, dumpOption);
170 
171     sem_post(&g_heapdumpCnt);
172 #endif // ENABLE_DUMP_IN_FAULTLOG
173 #else
174     LOG_ECMA(ERROR) << "Not support arkcompiler heap snapshot";
175 #endif // ECMASCRIPT_SUPPORT_SNAPSHOT
176 }
177 
178 // tid = 0: dump all vm; tid != 0: dump tid vm, hidumper.
DumpHeapSnapshot(const EcmaVM * vm,const DumpSnapShotOption & dumpOption,uint32_t tid)179 void DFXJSNApi::DumpHeapSnapshot([[maybe_unused]] const EcmaVM *vm,
180                                  [[maybe_unused]] const DumpSnapShotOption &dumpOption, [[maybe_unused]] uint32_t tid)
181 {
182     const int THREAD_COUNT = 1;
183     if (vm->IsWorkerThread()) {
184         LOG_ECMA(ERROR) << "this is a workthread!";
185         return;
186     }
187     sem_init(&g_heapdumpCnt, 0, THREAD_COUNT);
188     uint32_t curTid = vm->GetTid();
189     LOG_ECMA(INFO) << "DumpHeapSnapshot tid " << tid << " curTid " << curTid;
190     DumpHeapSnapshotWithVm(vm, dumpOption, tid);
191 }
192 
DumpHeapSnapshotWithVm(const EcmaVM * vm,const DumpSnapShotOption & dumpOption,uint32_t tid)193 void DFXJSNApi::DumpHeapSnapshotWithVm([[maybe_unused]] const EcmaVM *vm,
194                                        [[maybe_unused]] const DumpSnapShotOption &dumpOption,
195                                        [[maybe_unused]] uint32_t tid)
196 {
197 #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT)
198 #if defined(ENABLE_DUMP_IN_FAULTLOG)
199     uv_loop_t *loop = reinterpret_cast<uv_loop_t *>(vm->GetLoop());
200     if (loop == nullptr || uv_loop_alive(loop) == 0) {
201         LOG_ECMA(ERROR) << "loop nullptr or uv_loop_alive dead";
202         return;
203     }
204     struct DumpForSnapShotStruct *dumpStruct = new DumpForSnapShotStruct();
205     dumpStruct->vm = vm;
206     dumpStruct->dumpOption = dumpOption;
207     uv_work_t *work = new(std::nothrow) uv_work_t;
208     if (work == nullptr) {
209         LOG_ECMA(ERROR) << "work nullptr";
210         delete dumpStruct;
211         return;
212     }
213     work->data = static_cast<void *>(dumpStruct);
214 
215     uint32_t curTid = vm->GetTid();
216     int ret = 0;
217     if (tid == 0 || tid == curTid) {
218         ret = uv_queue_work(loop, work, [](uv_work_t *) {}, [](uv_work_t *work, int32_t) {
219             struct DumpForSnapShotStruct *dump = static_cast<struct DumpForSnapShotStruct *>(work->data);
220             DFXJSNApi::GetHeapPrepare(dump->vm);
221             DumpSnapShotOption dumpOption = dump->dumpOption;
222             DumpHeapSnapshot(dump->vm, dumpOption);
223             delete dump;
224             delete work;
225         });
226     } else {
227         delete dumpStruct;
228         delete work;
229     }
230 
231     // dump worker vm
232     const_cast<EcmaVM *>(vm)->EnumerateWorkerVm([&](const EcmaVM *workerVm) -> void {
233         uint32_t curTid = workerVm->GetTid();
234         LOG_ECMA(INFO) << "DumpHeapSnapshot workthread curTid " << curTid;
235         DumpHeapSnapshotWithVm(workerVm, dumpOption, tid);
236         return;
237     });
238 
239     if (ret != 0) {
240         LOG_ECMA(ERROR) << "uv_queue_work fail ret " << ret;
241         delete dumpStruct;
242         delete work;
243     }
244 #endif
245 #endif
246 }
247 
248 // tid = 0: TriggerGC all vm; tid != 0: TriggerGC tid vm
TriggerGC(const EcmaVM * vm,uint32_t tid)249 void DFXJSNApi::TriggerGC([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] uint32_t tid)
250 {
251     if (vm->IsWorkerThread()) {
252         LOG_ECMA(ERROR) << "this is a workthread!";
253         return;
254     }
255     // triggerGC host vm
256     uint32_t curTid = vm->GetTid();
257     LOG_ECMA(INFO) << "TriggerGC tid " << tid << " curTid " << curTid;
258     if (tid == 0 || tid == curTid) {
259         TriggerGCWithVm(vm);
260     }
261     // triggerGC worker vm
262     const_cast<EcmaVM *>(vm)->EnumerateWorkerVm([&](const EcmaVM *workerVm) -> void {
263         curTid = workerVm->GetTid();
264         LOG_ECMA(INFO) << "TriggerGC tid " << tid << " curTid " << curTid;
265         if (tid == 0 || tid == curTid) {
266             TriggerGCWithVm(workerVm);
267             return;
268         }
269     });
270     // triggerSharedFullGC
271     TriggerSharedGCWithVm(vm);
272 }
273 
TriggerSharedGCWithVm(const EcmaVM * vm)274 void DFXJSNApi::TriggerSharedGCWithVm([[maybe_unused]] const EcmaVM *vm)
275 {
276 #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT)
277 #if defined(ENABLE_DUMP_IN_FAULTLOG)
278     uv_loop_t *loop = reinterpret_cast<uv_loop_t *>(vm->GetLoop());
279     if (loop == nullptr) {
280         LOG_ECMA(ERROR) << "loop nullptr";
281         return;
282     }
283     if (uv_loop_alive(loop) == 0) {
284         LOG_ECMA(ERROR) << "uv_loop_alive dead";
285         return;
286     }
287     uv_work_t *work = new(std::nothrow) uv_work_t;
288     if (work == nullptr) {
289         LOG_ECMA(FATAL) << "DFXJSNApi::TriggerGCWithVm:work is nullptr";
290         return;
291     }
292     work->data = static_cast<void *>(const_cast<EcmaVM *>(vm));
293     int ret = uv_queue_work(loop, work, [](uv_work_t *) {}, [](uv_work_t *work, int32_t) {
294         EcmaVM *vm = static_cast<EcmaVM *>(work->data);
295         ecmascript::SharedHeap* sHeap = ecmascript::SharedHeap::GetInstance();
296         JSThread *thread = vm->GetJSThread();
297         ecmascript::ThreadManagedScope managedScope(thread);
298         sHeap->CollectGarbage<ecmascript::TriggerGCType::SHARED_FULL_GC,
299             ecmascript::GCReason::TRIGGER_BY_MEM_TOOLS>(thread);
300         delete work;
301     });
302     if (ret != 0) {
303         LOG_ECMA(ERROR) << "uv_queue_work fail ret " << ret;
304         delete work;
305     }
306 #endif
307 #endif
308 }
309 
TriggerGCWithVm(const EcmaVM * vm)310 void DFXJSNApi::TriggerGCWithVm([[maybe_unused]] const EcmaVM *vm)
311 {
312 #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT)
313 #if defined(ENABLE_DUMP_IN_FAULTLOG)
314     uv_loop_t *loop = reinterpret_cast<uv_loop_t *>(vm->GetLoop());
315     if (loop == nullptr) {
316         LOG_ECMA(ERROR) << "loop nullptr";
317         return;
318     }
319     if (uv_loop_alive(loop) == 0) {
320         LOG_ECMA(ERROR) << "uv_loop_alive dead";
321         return;
322     }
323     uv_work_t *work = new(std::nothrow) uv_work_t;
324     if (work == nullptr) {
325         LOG_ECMA(FATAL) << "DFXJSNApi::TriggerGCWithVm:work is nullptr";
326         return;
327     }
328     work->data = static_cast<void *>(const_cast<EcmaVM *>(vm));
329     int ret = uv_queue_work(loop, work, [](uv_work_t *) {}, [](uv_work_t *work, int32_t) {
330         EcmaVM *vm = static_cast<EcmaVM *>(work->data);
331         ecmascript::ThreadManagedScope managedScope(vm->GetJSThread());
332         vm->CollectGarbage(ecmascript::TriggerGCType::FULL_GC, ecmascript::GCReason::TRIGGER_BY_MEM_TOOLS);
333         delete work;
334     });
335     if (ret != 0) {
336         LOG_ECMA(ERROR) << "uv_queue_work fail ret " << ret;
337         delete work;
338     }
339 #endif
340 #endif
341 }
342 
DestroyHeapProfiler(const EcmaVM * vm)343 void DFXJSNApi::DestroyHeapProfiler([[maybe_unused]] const EcmaVM *vm)
344 {
345 #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT)
346     ecmascript::ThreadManagedScope managedScope(vm->GetJSThread());
347     ecmascript::HeapProfilerInterface::Destroy(const_cast<EcmaVM *>(vm));
348 #else
349     LOG_ECMA(ERROR) << "Not support arkcompiler heap snapshot";
350 #endif
351 }
352 
BuildNativeAndJsStackTrace(const EcmaVM * vm,std::string & stackTraceStr)353 bool DFXJSNApi::BuildNativeAndJsStackTrace(const EcmaVM *vm, std::string &stackTraceStr)
354 {
355     stackTraceStr = ecmascript::JsStackInfo::BuildJsStackTrace(vm->GetAssociatedJSThread(), true);
356     if (stackTraceStr.empty()) {
357         return false;
358     }
359     return true;
360 }
361 
BuildJsStackTrace(const EcmaVM * vm,std::string & stackTraceStr)362 bool DFXJSNApi::BuildJsStackTrace(const EcmaVM *vm, std::string &stackTraceStr)
363 {
364     JSThread *thread = vm->GetAssociatedJSThread();
365     ecmascript::ThreadManagedScope managedScope(thread);
366     bool needUnbindMutator = false;
367     if (g_isEnableCMCGC) {
368         common::Mutator *mutator = reinterpret_cast<common::Mutator *>(thread->GetThreadHolder()->GetMutator());
369         needUnbindMutator = common::BaseRuntime::GetInstance()->GetMutatorManager().BindMutatorOnly(mutator);
370     }
371     stackTraceStr = ecmascript::JsStackInfo::BuildJsStackTrace(thread, false);
372     if (needUnbindMutator) {
373         common::BaseRuntime::GetInstance()->GetMutatorManager().UnbindMutatorOnly();
374     }
375     if (stackTraceStr.empty()) {
376         return false;
377     }
378     return true;
379 }
380 
StartHeapTracking(const EcmaVM * vm,double timeInterval,bool isVmMode,Stream * stream,bool traceAllocation,bool newThread)381 bool DFXJSNApi::StartHeapTracking([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] double timeInterval,
382                                   [[maybe_unused]] bool isVmMode, [[maybe_unused]] Stream *stream,
383                                   [[maybe_unused]] bool traceAllocation, [[maybe_unused]] bool newThread)
384 {
385 #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT)
386     ecmascript::base::BlockHookScope blockScope;
387     ecmascript::ThreadManagedScope managedScope(vm->GetJSThread());
388     ecmascript::HeapProfilerInterface *heapProfile = ecmascript::HeapProfilerInterface::GetInstance(
389         const_cast<EcmaVM *>(vm));
390     return heapProfile->StartHeapTracking(timeInterval, isVmMode, stream, traceAllocation, newThread);
391 #else
392     LOG_ECMA(ERROR) << "Not support arkcompiler heap tracking";
393     return false;
394 #endif
395 }
396 
UpdateHeapTracking(const EcmaVM * vm,Stream * stream)397 bool DFXJSNApi::UpdateHeapTracking([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] Stream *stream)
398 {
399 #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT)
400     ecmascript::base::BlockHookScope blockScope;
401     ecmascript::ThreadManagedScope managedScope(vm->GetJSThread());
402     ecmascript::HeapProfilerInterface *heapProfile = ecmascript::HeapProfilerInterface::GetInstance(
403         const_cast<EcmaVM *>(vm));
404     return heapProfile->UpdateHeapTracking(stream);
405 #else
406     LOG_ECMA(ERROR) << "Not support arkcompiler heap tracking";
407     return false;
408 #endif
409 }
410 
StopHeapTracking(const EcmaVM * vm,const std::string & filePath,bool newThread)411 bool DFXJSNApi::StopHeapTracking([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] const std::string &filePath,
412                                  [[maybe_unused]] bool newThread)
413 {
414 #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT)
415     FileStream stream(filePath);
416     return StopHeapTracking(vm, &stream, nullptr, newThread);
417 #else
418     LOG_ECMA(ERROR) << "Not support arkcompiler heap tracking";
419     return false;
420 #endif
421 }
422 
StopHeapTracking(const EcmaVM * vm,Stream * stream,Progress * progress,bool newThread)423 bool DFXJSNApi::StopHeapTracking([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] Stream* stream,
424                                  [[maybe_unused]] Progress *progress, [[maybe_unused]] bool newThread)
425 {
426 #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT)
427     ecmascript::base::BlockHookScope blockScope;
428     ecmascript::ThreadManagedScope managedScope(vm->GetJSThread());
429     bool result = false;
430     ecmascript::HeapProfilerInterface *heapProfile = ecmascript::HeapProfilerInterface::GetInstance(
431         const_cast<EcmaVM *>(vm));
432     result = heapProfile->StopHeapTracking(stream, progress, newThread);
433     ecmascript::HeapProfilerInterface::Destroy(const_cast<EcmaVM *>(vm));
434     return result;
435 #else
436     LOG_ECMA(ERROR) << "Not support arkcompiler heap tracking";
437     return false;
438 #endif
439 }
440 
PrintStatisticResult(const EcmaVM * vm)441 void DFXJSNApi::PrintStatisticResult(const EcmaVM *vm)
442 {
443     ecmascript::GCStats gcstats(vm->GetHeap());
444     gcstats.PrintStatisticResult();
445 }
446 
StartRuntimeStat(EcmaVM * vm)447 void DFXJSNApi::StartRuntimeStat(EcmaVM *vm)
448 {
449     vm->GetJSThread()->GetEcmaVM()->SetRuntimeStatEnable(true);
450 }
451 
StopRuntimeStat(EcmaVM * vm)452 void DFXJSNApi::StopRuntimeStat(EcmaVM *vm)
453 {
454     vm->GetJSThread()->GetEcmaVM()->SetRuntimeStatEnable(false);
455 }
456 
GetArrayBufferSizeForCMCGC()457 size_t GetArrayBufferSizeForCMCGC()
458 {
459     size_t result = 0;
460     auto visitor = [&result](common::BaseObject *obj) {
461         panda::ecmascript::JSTaggedValue entry = panda::ecmascript::JSTaggedValue(
462             reinterpret_cast<panda::ecmascript::JSTaggedType>(obj));
463         panda::ecmascript::TaggedObject *taggedObj = entry.GetTaggedObject();
464         panda::ecmascript::JSHClass* jsClass = taggedObj->GetClass();
465         result += jsClass->IsArrayBuffer() ? jsClass->GetObjectSize() : 0;
466     };
467     common::Heap::GetHeap().ForEachObject(visitor, true);
468     return result;
469 }
470 
GetArrayBufferSize(const EcmaVM * vm)471 size_t DFXJSNApi::GetArrayBufferSize(const EcmaVM *vm)
472 {
473     if (g_isEnableCMCGC) {
474         return GetArrayBufferSizeForCMCGC();
475     }
476     ecmascript::ThreadManagedScope managedScope(vm->GetJSThread());
477     return vm->GetHeap()->GetArrayBufferSize();
478 }
479 
GetHeapTotalSize(const EcmaVM * vm)480 size_t DFXJSNApi::GetHeapTotalSize(const EcmaVM *vm)
481 {
482     if (g_isEnableCMCGC) {
483         return common::Heap::GetHeap().GetCurrentCapacity();
484     }
485     return vm->GetHeap()->GetCommittedSize();
486 }
487 
GetHeapUsedSize(const EcmaVM * vm)488 size_t DFXJSNApi::GetHeapUsedSize(const EcmaVM *vm)
489 {
490     if (g_isEnableCMCGC) {
491         return common::Heap::GetHeap().GetSurvivedSize();
492     }
493     ecmascript::ThreadManagedScope managedScope(vm->GetJSThread());
494     return vm->GetHeap()->GetLiveObjectSize();
495 }
496 
GetHeapObjectSize(const EcmaVM * vm)497 size_t DFXJSNApi::GetHeapObjectSize(const EcmaVM *vm)
498 {
499     if (g_isEnableCMCGC) {
500         return common::Heap::GetHeap().GetAllocatedSize();
501     }
502     return vm->GetHeap()->GetHeapObjectSize();
503 }
504 
GetHeapLimitSize(const EcmaVM * vm)505 size_t DFXJSNApi::GetHeapLimitSize(const EcmaVM *vm)
506 {
507     if (g_isEnableCMCGC) {
508         return common::Heap::GetHeap().GetMaxCapacity();
509     }
510     return vm->GetHeap()->GetHeapLimitSize();
511 }
512 
GetProcessHeapLimitSize()513 size_t DFXJSNApi::GetProcessHeapLimitSize()
514 {
515     if (g_isEnableCMCGC) {
516         return common::Heap::GetHeap().GetMaxCapacity();
517     }
518     return ecmascript::MemMapAllocator::GetInstance()->GetCapacity();
519 }
520 
GetGCCount(const EcmaVM * vm)521 size_t DFXJSNApi::GetGCCount(const EcmaVM *vm)
522 {
523     if (vm->IsWorkerThread()) {
524         return vm->GetEcmaGCStats()->GetGCCount();
525     }
526     return vm->GetEcmaGCStats()->GetGCCount() +
527         ecmascript::SharedHeap::GetInstance()->GetEcmaGCStats()->GetGCCount();
528 }
529 
GetGCDuration(const EcmaVM * vm)530 size_t DFXJSNApi::GetGCDuration(const EcmaVM *vm)
531 {
532     if (vm->IsWorkerThread()) {
533         return vm->GetEcmaGCStats()->GetGCDuration();
534     }
535     return vm->GetEcmaGCStats()->GetGCDuration() +
536         ecmascript::SharedHeap::GetInstance()->GetEcmaGCStats()->GetGCDuration();
537 }
538 
GetAccumulatedAllocateSize(const EcmaVM * vm)539 size_t DFXJSNApi::GetAccumulatedAllocateSize(const EcmaVM *vm)
540 {
541     if (g_isEnableCMCGC) {
542         return common::Heap::GetHeap().GetAccumulatedAllocateSize();
543     }
544     if (vm->IsWorkerThread()) {
545         return vm->GetEcmaGCStats()->GetAccumulatedAllocateSize();
546     }
547     return vm->GetEcmaGCStats()->GetAccumulatedAllocateSize() +
548         ecmascript::SharedHeap::GetInstance()->GetEcmaGCStats()->GetAccumulatedAllocateSize();
549 }
550 
GetAccumulatedFreeSize(const EcmaVM * vm)551 size_t DFXJSNApi::GetAccumulatedFreeSize(const EcmaVM *vm)
552 {
553     if (g_isEnableCMCGC) {
554         return common::Heap::GetHeap().GetAccumulatedFreeSize();
555     }
556     if (vm->IsWorkerThread()) {
557         return vm->GetEcmaGCStats()->GetAccumulatedFreeSize();
558     }
559     return vm->GetEcmaGCStats()->GetAccumulatedFreeSize() +
560         ecmascript::SharedHeap::GetInstance()->GetEcmaGCStats()->GetAccumulatedFreeSize();
561 }
562 
GetFullGCLongTimeCount(const EcmaVM * vm)563 size_t DFXJSNApi::GetFullGCLongTimeCount(const EcmaVM *vm)
564 {
565     return vm->GetEcmaGCStats()->GetFullGCLongTimeCount();
566 }
567 
GetHeapPrepare(const EcmaVM * vm)568 void DFXJSNApi::GetHeapPrepare(const EcmaVM *vm)
569 {
570     ecmascript::ThreadManagedScope managedScope(vm->GetJSThread());
571     const_cast<ecmascript::Heap *>(vm->GetHeap())->GetHeapPrepare();
572 }
573 
SetJsDumpThresholds(EcmaVM * vm,size_t thresholds)574 void DFXJSNApi::SetJsDumpThresholds([[maybe_unused]] EcmaVM *vm, [[maybe_unused]] size_t thresholds)
575 {
576 #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT) && defined(PANDA_TARGET_OHOS) && defined(ENABLE_HISYSEVENT)
577     vm->GetHeap()->SetJsDumpThresholds(thresholds);
578 #else
579     LOG_ECMA(ERROR) << "Not support set jsdump thresholds";
580 #endif
581 }
582 
SetAppFreezeFilterCallback(const EcmaVM * vm,AppFreezeFilterCallback cb)583 void DFXJSNApi::SetAppFreezeFilterCallback([[maybe_unused]] const EcmaVM *vm, AppFreezeFilterCallback cb)
584 {
585     if (ecmascript::Runtime::GetInstance()->GetAppFreezeFilterCallback() == nullptr && cb != nullptr) {
586         ecmascript::Runtime::GetInstance()->SetAppFreezeFilterCallback(cb);
587     }
588 }
589 
NotifyApplicationState(EcmaVM * vm,bool inBackground)590 void DFXJSNApi::NotifyApplicationState(EcmaVM *vm, bool inBackground)
591 {
592     ecmascript::ThreadManagedScope managedScope(vm->GetJSThread());
593     const_cast<ecmascript::Heap *>(vm->GetHeap())->ChangeGCParams(inBackground);
594     ecmascript::Jit::GetInstance()->ChangeTaskPoolState(inBackground);
595 }
596 
NotifyIdleStatusControl(const EcmaVM * vm,std::function<void (bool)> callback)597 void DFXJSNApi::NotifyIdleStatusControl(const EcmaVM *vm, std::function<void(bool)> callback)
598 {
599     const_cast<ecmascript::Heap *>(vm->GetHeap())->InitializeIdleStatusControl(callback);
600 }
601 
NotifyIdleTime(const EcmaVM * vm,int idleMicroSec)602 void DFXJSNApi::NotifyIdleTime(const EcmaVM *vm, int idleMicroSec)
603 {
604     ecmascript::ThreadManagedScope managedScope(vm->GetJSThread());
605     const_cast<ecmascript::Heap *>(vm->GetHeap())->TriggerIdleCollection(idleMicroSec);
606 }
607 
NotifyMemoryPressure(EcmaVM * vm,bool inHighMemoryPressure)608 void DFXJSNApi::NotifyMemoryPressure(EcmaVM *vm, bool inHighMemoryPressure)
609 {
610     const_cast<ecmascript::Heap *>(vm->GetHeap())->NotifyMemoryPressure(inHighMemoryPressure);
611 }
612 
NotifyFinishColdStart(EcmaVM * vm,bool isConvinced)613 void DFXJSNApi::NotifyFinishColdStart(EcmaVM *vm, [[maybe_unused]] bool isConvinced)
614 {
615     ecmascript::ThreadManagedScope managedScope(vm->GetJSThread());
616 }
617 
NotifyHighSensitive(EcmaVM * vm,bool isStart)618 void DFXJSNApi::NotifyHighSensitive(EcmaVM *vm, bool isStart)
619 {
620     const_cast<ecmascript::Heap *>(vm->GetHeap())->NotifyHighSensitive(isStart);
621 }
622 
NotifyWarmStart(EcmaVM * vm)623 void DFXJSNApi::NotifyWarmStart(EcmaVM *vm)
624 {
625     LOG_ECMA(INFO) << "SmartGC: app warm start gc";
626     ecmascript::ThreadManagedScope managedScope(vm->GetJSThread());
627     if (AllowWarmStartGcRestrain(vm)) {
628         const_cast<ecmascript::Heap *>(vm->GetHeap())->NotifyWarmStartup();
629     }
630 }
631 
AllowWarmStartGcRestrain(EcmaVM * vm)632 bool DFXJSNApi::AllowWarmStartGcRestrain(EcmaVM *vm)
633 {
634     common::GCPhase gcPhase = vm->GetJSThread()->GetCMCGCPhase();
635     if (gcPhase > common::GCPhase::GC_PHASE_IDLE) {
636         LOG_ECMA(WARN) << "SmartGC: app warm start gc, but gc phase more than GC_PHASE_IDLE, skip";
637         return false;
638     }
639 
640     bool hasFinishedMark = vm->GetJSThread()->IsConcurrentMarkingOrFinished();
641     if (hasFinishedMark) {
642         LOG_ECMA(WARN) << "SmartGC: app warm start gc, but gc mark is concurrent marking or finished, skip";
643         return false;
644     }
645     ecmascript::StartupStatus status = const_cast<ecmascript::Heap *>(vm->GetHeap())->GetStartupStatus();
646     bool isGcRestraining = (status == ecmascript::StartupStatus::ON_STARTUP ||
647                             status == ecmascript::StartupStatus::JUST_FINISH_STARTUP);
648     if (isGcRestraining) {
649         LOG_ECMA(WARN) << "SmartGC: app warm start gc, but it is already in GC restraining now, skip";
650         return false;
651     }
652     return true;
653 }
654 
StopCpuProfilerForColdStart(const EcmaVM * vm)655 bool DFXJSNApi::StopCpuProfilerForColdStart([[maybe_unused]] const EcmaVM *vm)
656 {
657 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
658     bool success = false;
659     auto &options = const_cast<EcmaVM *>(vm)->GetJSOptions();
660     if (options.EnableCpuProfilerColdStartMainThread()) {
661         success = true;
662         DFXJSNApi::StopCpuProfilerForFile(vm);
663     }
664 
665     if (options.EnableCpuProfilerColdStartWorkerThread()) {
666         success = true;
667         const_cast<EcmaVM *>(vm)->EnumerateWorkerVm([&](const EcmaVM *workerVm) -> void {
668             if (workerVm->GetJSThread()->GetIsProfiling()) {
669                 DFXJSNApi::StopCpuProfilerForFile(workerVm);
670             }
671         });
672     }
673 
674     return success;
675 #else
676     LOG_ECMA(ERROR) << "Not support arkcompiler cpu profiler";
677     return false;
678 #endif
679 }
680 
681 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
CpuProfilerAnyTimeMainThread(const EcmaVM * vm)682 void DFXJSNApi::CpuProfilerAnyTimeMainThread(const EcmaVM *vm)
683 {
684     const uint8_t KILL_COUNT_FACTOR = 2;
685     if (killCount % KILL_COUNT_FACTOR == 0) {
686         uint8_t fileCount = killCount / KILL_COUNT_FACTOR + 1;
687         LOG_ECMA(INFO) << "Start CpuProfiler Any Time Main Thread, killCount = " << killCount;
688         std::string fileName = ConvertToStdString(const_cast<EcmaVM *>(vm)->GetBundleName())
689                                + "_" + std::to_string(fileCount) + ".cpuprofile";
690         if (!BuiltinsArkTools::CreateFile(fileName)) {
691             LOG_ECMA(ERROR) << "createFile failed " << fileName;
692         } else {
693             DFXJSNApi::StartCpuProfilerForFile(vm, fileName, CpuProfiler::INTERVAL_OF_INNER_START);
694         }
695     } else {
696         LOG_ECMA(INFO) << "Stop CpuProfiler Any Time Main Thread, killCount = " << killCount;
697         if (vm->GetJSThread()->GetIsProfiling()) {
698             DFXJSNApi::StopCpuProfilerForFile(vm);
699         }
700     }
701 }
702 #endif
703 
CpuProfilerSamplingAnyTime(const EcmaVM * vm)704 bool DFXJSNApi::CpuProfilerSamplingAnyTime([[maybe_unused]] const EcmaVM *vm)
705 {
706 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
707     (void)killCount;
708     bool success = false;
709     const uint8_t KILL_COUNT_FACTOR = 2;
710     auto &options = const_cast<EcmaVM *>(vm)->GetJSOptions();
711     if (options.EnableCpuProfilerAnyTimeMainThread()) {
712         success = true;
713         CpuProfilerAnyTimeMainThread(vm);
714     }
715 
716     if (options.EnableCpuProfilerAnyTimeWorkerThread()) {
717         success = true;
718         if (killCount % KILL_COUNT_FACTOR == 0) {
719             uint8_t fileCount = killCount / KILL_COUNT_FACTOR + 1;
720             LOG_ECMA(INFO) << "Start CpuProfiler Any Time Worker Thread, killCount = " << killCount;
721             const_cast<EcmaVM *>(vm)->EnumerateWorkerVm([&](const EcmaVM *workerVm) -> void {
722                 auto *thread = workerVm->GetAssociatedJSThread();
723                 std::string fileName = ConvertToStdString(workerVm->GetBundleName()) + "_"
724                                        + std::to_string(thread->GetThreadId()) + "_"
725                                        + std::to_string(fileCount) + ".cpuprofile";
726                 if (!BuiltinsArkTools::CreateFile(fileName)) {
727                     LOG_ECMA(ERROR) << "createFile failed " << fileName;
728                 } else {
729                     thread->SetCpuProfileName(fileName);
730                     thread->SetNeedProfiling(true);
731                 }
732             });
733         } else {
734             LOG_ECMA(INFO) << "Stop CpuProfiler Any Time Worker Thread, killCount = " << killCount;
735             const_cast<EcmaVM *>(vm)->EnumerateWorkerVm([&](const EcmaVM *workerVm) -> void {
736                 auto *thread = workerVm->GetAssociatedJSThread();
737                 if (thread->GetIsProfiling()) {
738                     DFXJSNApi::StopCpuProfilerForFile(workerVm);
739                 }
740                 thread->SetNeedProfiling(false);
741             });
742         }
743     }
744 
745     return success;
746 #else
747     LOG_ECMA(ERROR) << "Not support arkcompiler cpu profiler";
748     return false;
749 #endif
750 }
751 
StartCpuProfilerForFile(const EcmaVM * vm,const std::string & fileName,int interval)752 bool DFXJSNApi::StartCpuProfilerForFile([[maybe_unused]] const EcmaVM *vm,
753                                         [[maybe_unused]] const std::string &fileName,
754                                         [[maybe_unused]] int interval)
755 {
756 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
757     LOG_ECMA(INFO) << "DFXJSNApi::StartCpuProfilerForFile, vm = " << vm;
758     if (interval <= 0) {
759         LOG_ECMA(ERROR) << "DFXJSNApi::StartCpuProfilerForFile, interval <= 0";
760         return false;
761     }
762     if (vm == nullptr) {
763         LOG_ECMA(ERROR) << "DFXJSNApi::StartCpuProfilerForFile, vm == nullptr";
764         return false;
765     }
766     CpuProfiler *profiler = vm->GetProfiler();
767     if (profiler == nullptr) {
768         profiler = new CpuProfiler(vm, interval);
769         const_cast<EcmaVM *>(vm)->SetProfiler(profiler);
770     }
771     return profiler->StartCpuProfilerForFile(fileName);
772 #else
773     LOG_ECMA(ERROR) << "DFXJSNApi::StartCpuProfilerForFile, not support cpu profiler";
774     return false;
775 #endif
776 }
777 
StopCpuProfilerForFile(const EcmaVM * vm)778 void DFXJSNApi::StopCpuProfilerForFile([[maybe_unused]] const EcmaVM *vm)
779 {
780 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
781     LOG_ECMA(INFO) << "DFXJSNApi::StopCpuProfilerForFile, vm = " << vm;
782     if (vm == nullptr) {
783         LOG_ECMA(ERROR) << "DFXJSNApi::StopCpuProfilerForFile, vm == nullptr";
784         return;
785     }
786     CpuProfiler *profiler = vm->GetProfiler();
787     if (profiler == nullptr) {
788         LOG_ECMA(ERROR) << "DFXJSNApi::StopCpuProfilerForFile, profiler == nullptr";
789         return;
790     }
791     bool result = profiler->StopCpuProfilerForFile();
792     if (!result) {
793         LOG_ECMA(ERROR) << "DFXJSNApi::StopCpuProfilerForFile failed";
794         return;
795     }
796     delete profiler;
797     profiler = nullptr;
798     const_cast<EcmaVM *>(vm)->SetProfiler(nullptr);
799 #else
800     LOG_ECMA(ERROR) << "Not support arkcompiler cpu profiler";
801 #endif
802 }
803 
StartCpuProfilerForInfo(const EcmaVM * vm,int interval)804 bool DFXJSNApi::StartCpuProfilerForInfo([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] int interval)
805 {
806 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
807     LOG_ECMA(INFO) << "DFXJSNApi::StartCpuProfilerForInfo, vm = " << vm;
808     if (interval <= 0) {
809         LOG_ECMA(ERROR) << "DFXJSNApi::StartCpuProfilerForInfo, interval <= 0";
810         return false;
811     }
812     if (vm == nullptr) {
813         LOG_ECMA(ERROR) << "DFXJSNApi::StartCpuProfilerForInfo, vm == nullptr";
814         return false;
815     }
816     CpuProfiler *profiler = vm->GetProfiler();
817     if (profiler == nullptr) {
818         profiler = new CpuProfiler(vm, interval);
819         const_cast<EcmaVM *>(vm)->SetProfiler(profiler);
820     }
821     return profiler->StartCpuProfilerForInfo();
822 #else
823     LOG_ECMA(ERROR) << "DFXJSNApi::StartCpuProfilerForInfo, not support cpu profiler";
824     return false;
825 #endif
826 }
827 
StopCpuProfilerForInfo(const EcmaVM * vm)828 std::unique_ptr<ProfileInfo> DFXJSNApi::StopCpuProfilerForInfo([[maybe_unused]] const EcmaVM *vm)
829 {
830 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
831     LOG_ECMA(INFO) << "DFXJSNApi::StopCpuProfilerForInfo, vm = " << vm;
832     if (vm == nullptr) {
833         LOG_ECMA(ERROR) << "DFXJSNApi::StopCpuProfilerForInfo, vm == nullptr";
834         return nullptr;
835     }
836     CpuProfiler *profiler = vm->GetProfiler();
837     if (profiler == nullptr) {
838         LOG_ECMA(ERROR) << "DFXJSNApi::StopCpuProfilerForInfo, profiler == nullptr";
839         return nullptr;
840     }
841     std::unique_ptr<ProfileInfo> profileInfo;
842     bool result = profiler->StopCpuProfilerForInfo(profileInfo);
843     if (!result) {
844         LOG_ECMA(ERROR) << "DFXJSNApi::StopCpuProfilerForInfo failed";
845         return nullptr;
846     }
847     delete profiler;
848     profiler = nullptr;
849     const_cast<EcmaVM *>(vm)->SetProfiler(nullptr);
850     return profileInfo;
851 #else
852     LOG_ECMA(ERROR) << "Not support arkcompiler cpu profiler";
853     return nullptr;
854 #endif
855 }
856 
SetCpuSamplingInterval(const EcmaVM * vm,int interval)857 void DFXJSNApi::SetCpuSamplingInterval([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] int interval)
858 {
859 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
860     if (interval < 0) {
861         LOG_ECMA(ERROR) << "Sampling interval is illegal";
862         return;
863     }
864     LOG_ECMA(INFO) << "SetCpuProfilerSamplingInterval, Sampling interval is: " << interval;
865     if (vm == nullptr) {
866         return;
867     }
868     CpuProfiler *profiler = vm->GetProfiler();
869     if (profiler == nullptr) {
870         profiler = new CpuProfiler(vm, interval);
871         const_cast<EcmaVM *>(vm)->SetProfiler(profiler);
872         return;
873     }
874     profiler->SetCpuSamplingInterval(interval);
875 #else
876     LOG_ECMA(ERROR) << "Not support arkcompiler cpu profiler";
877 #endif
878 }
879 
EnableSeriliazationTimeoutCheck(const EcmaVM * ecmaVM,int32_t threshold)880 void DFXJSNApi::EnableSeriliazationTimeoutCheck(const EcmaVM *ecmaVM, int32_t threshold)
881 {
882     ecmaVM->GetJsDebuggerManager()->EnableSerializationTimeoutCheck();
883     ecmaVM->GetJsDebuggerManager()->SetSerializationCheckThreshold(threshold);
884 }
885 
DisableSeriliazationTimeoutCheck(const EcmaVM * ecmaVM)886 void DFXJSNApi::DisableSeriliazationTimeoutCheck(const EcmaVM *ecmaVM)
887 {
888     ecmaVM->GetJsDebuggerManager()->DisableSerializationTimeoutCheck();
889 }
890 
SuspendVM(const EcmaVM * vm)891 bool DFXJSNApi::SuspendVM([[maybe_unused]] const EcmaVM *vm)
892 {
893 #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT)
894     ecmascript::VmThreadControl* vmThreadControl = vm->GetAssociatedJSThread()->GetVmThreadControl();
895     return vmThreadControl->NotifyVMThreadSuspension();
896 #else
897     LOG_ECMA(ERROR) << "Not support arkcompiler snapshot";
898     return false;
899 #endif
900 }
901 
ResumeVM(const EcmaVM * vm)902 void DFXJSNApi::ResumeVM([[maybe_unused]] const EcmaVM *vm)
903 {
904 #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT)
905     ecmascript::VmThreadControl* vmThreadControl = vm->GetAssociatedJSThread()->GetVmThreadControl();
906     vmThreadControl->ResumeVM();
907 #else
908     LOG_ECMA(ERROR) << "Not support arkcompiler snapshot";
909 #endif
910 }
911 
IsSuspended(const EcmaVM * vm)912 bool DFXJSNApi::IsSuspended([[maybe_unused]] const EcmaVM *vm)
913 {
914 #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT)
915     ecmascript::VmThreadControl* vmThreadControl = vm->GetAssociatedJSThread()->GetVmThreadControl();
916     return vmThreadControl->IsSuspended();
917 #else
918     LOG_ECMA(ERROR) << "Not support arkcompiler snapshot";
919     return false;
920 #endif
921 }
922 
TerminateExecution(const EcmaVM * vm)923 void DFXJSNApi::TerminateExecution(const EcmaVM *vm)
924 {
925     ecmascript::VmThreadControl* vmThreadControl = vm->GetAssociatedJSThread()->GetVmThreadControl();
926     vmThreadControl->RequestTerminateExecution();
927 }
928 
CheckSafepoint(const EcmaVM * vm)929 bool DFXJSNApi::CheckSafepoint([[maybe_unused]] const EcmaVM *vm)
930 {
931 #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT)
932     ecmascript::JSThread* thread = vm->GetJSThread();
933     return thread->CheckSafepoint();
934 #else
935     LOG_ECMA(ERROR) << "Not support arkcompiler snapshot";
936     return false;
937 #endif
938 }
939 
BuildJsStackInfoList(const EcmaVM * hostVm,uint32_t tid,std::vector<JsFrameInfo> & jsFrames)940 bool DFXJSNApi::BuildJsStackInfoList(const EcmaVM *hostVm, uint32_t tid, std::vector<JsFrameInfo>& jsFrames)
941 {
942     EcmaVM *vm;
943     if (hostVm->GetAssociatedJSThread()->GetThreadId() == tid) {
944         vm = const_cast<EcmaVM*>(hostVm);
945     } else {
946         vm = const_cast<EcmaVM*>(hostVm)->GetWorkerVm(tid);
947         if (vm == nullptr) {
948             return false;
949         }
950     }
951     jsFrames = ecmascript::JsStackInfo::BuildJsStackInfo(vm->GetAssociatedJSThread());
952     if (jsFrames.size() > 0) {
953         return true;
954     }
955     return false;
956 }
957 
958 //When some objects invoke GetObjectHash, the return result is 0.
959 //The GetObjectHashCode function is added to rectify the fault.
GetObjectHash(const EcmaVM * vm,Local<JSValueRef> nativeObject)960 int32_t DFXJSNApi::GetObjectHash(const EcmaVM *vm, Local<JSValueRef> nativeObject)
961 {
962     JSHandle<JSTaggedValue> obj = JSNApiHelper::ToJSHandle(nativeObject);
963     return ecmascript::tooling::DebuggerApi::GetObjectHash(vm, obj);
964 }
965 
GetObjectHashCode(const EcmaVM * vm,Local<JSValueRef> nativeObject)966 int32_t DFXJSNApi::GetObjectHashCode(const EcmaVM *vm, Local<JSValueRef> nativeObject)
967 {
968     JSHandle<JSTaggedValue> obj = JSNApiHelper::ToJSHandle(nativeObject);
969     return ecmascript::tooling::DebuggerApi::GetObjectHashCode(vm, obj);
970 }
971 
StartSampling(const EcmaVM * vm,uint64_t samplingInterval)972 bool DFXJSNApi::StartSampling([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] uint64_t samplingInterval)
973 {
974 #if defined(ECMASCRIPT_SUPPORT_HEAPSAMPLING)
975     ecmascript::HeapProfilerInterface *heapProfile = ecmascript::HeapProfilerInterface::GetInstance(
976         const_cast<EcmaVM *>(vm));
977     return heapProfile->StartHeapSampling(samplingInterval);
978 #else
979     LOG_ECMA(ERROR) << "Not support arkcompiler heap sampling";
980     return false;
981 #endif
982 }
983 
GetAllocationProfile(const EcmaVM * vm)984 const SamplingInfo *DFXJSNApi::GetAllocationProfile([[maybe_unused]] const EcmaVM *vm)
985 {
986 #if defined(ECMASCRIPT_SUPPORT_HEAPSAMPLING)
987     ecmascript::HeapProfilerInterface *heapProfile = ecmascript::HeapProfilerInterface::GetInstance(
988         const_cast<EcmaVM *>(vm));
989     return heapProfile->GetAllocationProfile();
990 #else
991     LOG_ECMA(ERROR) << "Not support arkcompiler heap sampling";
992     return nullptr;
993 #endif
994 }
995 
StopSampling(const EcmaVM * vm)996 void DFXJSNApi::StopSampling([[maybe_unused]] const EcmaVM *vm)
997 {
998 #if defined(ECMASCRIPT_SUPPORT_HEAPSAMPLING)
999     ecmascript::HeapProfilerInterface *heapProfile = ecmascript::HeapProfilerInterface::GetInstance(
1000         const_cast<EcmaVM *>(vm));
1001     heapProfile->StopHeapSampling();
1002 #else
1003     LOG_ECMA(ERROR) << "Not support arkcompiler heap sampling";
1004 #endif
1005 }
1006 
1007 // release or debug hap : aa start -p 'dumpheap'
1008 //                        aa start -p 'profile'
StartProfiler(EcmaVM * vm,const ProfilerOption & option,int tid,int32_t instanceId,const DebuggerPostTask & debuggerPostTask,bool isDebugApp)1009 bool DFXJSNApi::StartProfiler(EcmaVM *vm, const ProfilerOption &option, int tid,
1010                               int32_t instanceId, const DebuggerPostTask &debuggerPostTask, bool isDebugApp)
1011 {
1012     LOG_ECMA(INFO) << "DFXJSNApi::StartProfiler, type = " << (int)option.profilerType
1013         << ", tid = " << tid << ", isDebugApp = " << isDebugApp;
1014     JSNApi::DebugOption debugOption;
1015     debugOption.libraryPath = option.libraryPath;
1016     if (option.profilerType == ProfilerType::CPU_PROFILER) {
1017         debugOption.isDebugMode = false;
1018         if (JSNApi::NotifyDebugMode(tid, vm, debugOption, instanceId, debuggerPostTask, isDebugApp)) {
1019             return StartCpuProfilerForInfo(vm, option.interval);
1020         } else {
1021             LOG_ECMA(ERROR) << "DFXJSNApi::StartProfiler, NotifyDebugMode failed";
1022             return false;
1023         }
1024     } else {
1025         debugOption.isDebugMode = true;
1026         return JSNApi::NotifyDebugMode(tid, vm, debugOption, instanceId, debuggerPostTask, isDebugApp);
1027     }
1028 }
1029 
ResumeVMById(EcmaVM * hostVm,uint32_t tid)1030 void DFXJSNApi::ResumeVMById(EcmaVM *hostVm, uint32_t tid)
1031 {
1032     if (hostVm->GetAssociatedJSThread()->GetThreadId() == tid) {
1033         ResumeVM(hostVm);
1034     } else {
1035         hostVm->ResumeWorkerVm(tid);
1036     }
1037 }
1038 
SuspendVMById(EcmaVM * hostVm,uint32_t tid)1039 bool DFXJSNApi::SuspendVMById(EcmaVM *hostVm, uint32_t tid)
1040 {
1041     bool success = false;
1042     if (hostVm->GetAssociatedJSThread()->GetThreadId() == tid) {
1043         success = SuspendVM(hostVm);
1044         LOG_ECMA(INFO) << "The main thread, SuspendVMById succeeded: " << success;
1045         return success;
1046     } else {
1047         success = hostVm->SuspendWorkerVm(tid);
1048         LOG_ECMA(INFO) << "The worker thread, SuspendVMById succeeded: " << success;
1049         return success;
1050     }
1051 }
1052 
StartTracing(const EcmaVM * vm,std::string & categories)1053 bool DFXJSNApi::StartTracing([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] std::string &categories)
1054 {
1055 #if defined(ECMASCRIPT_SUPPORT_TRACING)
1056     if (vm == nullptr) {
1057         return false;
1058     }
1059     Tracing *tracing = vm->GetTracing();
1060     if (tracing == nullptr) {
1061         tracing = new Tracing(vm);
1062         const_cast<EcmaVM *>(vm)->SetTracing(tracing);
1063     }
1064     tracing->StartTracing(categories);
1065     return true;
1066 #else
1067     LOG_ECMA(ERROR) << "Not support arkcompiler tracing";
1068     return false;
1069 #endif
1070 }
1071 
StopTracing(const EcmaVM * vm)1072 std::unique_ptr<std::vector<TraceEvent>> DFXJSNApi::StopTracing([[maybe_unused]] const EcmaVM *vm)
1073 {
1074 #if defined(ECMASCRIPT_SUPPORT_TRACING)
1075     if (vm == nullptr) {
1076         return nullptr;
1077     }
1078     Tracing *tracing = vm->GetTracing();
1079     if (tracing == nullptr) {
1080         LOG_ECMA(ERROR) << "StopTracing tracing is nullptr";
1081         return nullptr;
1082     }
1083     auto traceEvents = tracing->StopTracing();
1084     if (traceEvents == nullptr) {
1085         LOG_ECMA(ERROR) << "trace events is nullptr";
1086     }
1087     delete tracing;
1088     tracing = nullptr;
1089     const_cast<EcmaVM *>(vm)->SetTracing(nullptr);
1090     return traceEvents;
1091 #else
1092     LOG_ECMA(ERROR) << "Not support arkcompiler tracing";
1093     return nullptr;
1094 #endif
1095 }
1096 
GetTracingBufferUseage(const EcmaVM * vm,double & percentFull,uint32_t & eventCount,double & value)1097 void DFXJSNApi::GetTracingBufferUseage([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] double &percentFull,
1098                                        [[maybe_unused]] uint32_t &eventCount, [[maybe_unused]] double &value)
1099 {
1100 #if defined(ECMASCRIPT_SUPPORT_TRACING)
1101     if (vm == nullptr) {
1102         return;
1103     }
1104     ecmascript::Tracing *tracing = vm->GetTracing();
1105     if (tracing == nullptr) {
1106         LOG_ECMA(ERROR) << "GetTracingBufferUseage tracing is nullptr";
1107     } else {
1108         tracing->GetBufferUseage(percentFull, eventCount, value);
1109     }
1110 #else
1111     LOG_ECMA(ERROR) << "Not support arkcompiler tracing";
1112 #endif
1113 }
1114 
TranslateJSStackInfo(const EcmaVM * vm,std::string & url,int32_t & line,int32_t & column,std::string & packageName)1115 void DFXJSNApi::TranslateJSStackInfo(const EcmaVM *vm, std::string &url, int32_t &line, int32_t &column,
1116     std::string &packageName)
1117 {
1118     auto cb = vm->GetSourceMapTranslateCallback();
1119     if (cb == nullptr) {
1120         LOG_ECMA(ERROR) << "Translate failed, callback function is nullptr.";
1121     } else if (!cb(url, line, column, packageName)) {
1122         LOG_ECMA(ERROR) << "Translate failed, url: " << url;
1123     }
1124 }
1125 
GetCurrentThreadId()1126 uint32_t DFXJSNApi::GetCurrentThreadId()
1127 {
1128     return JSThread::GetCurrentThreadId();
1129 }
1130 
RegisterAsyncDetectCallBack(const EcmaVM * vm)1131 void DFXJSNApi::RegisterAsyncDetectCallBack(const EcmaVM *vm)
1132 {
1133     vm->GetAsyncStackTrace()->RegisterAsyncDetectCallBack();
1134 }
1135 
GetMainThreadStackTrace(const EcmaVM * vm,std::string & stackTraceStr)1136 void DFXJSNApi::GetMainThreadStackTrace(const EcmaVM *vm, std::string &stackTraceStr)
1137 {
1138     auto thread = vm->GetJSThread();
1139     if (thread->IsMainThread()) {
1140         stackTraceStr = ecmascript::JsStackInfo::BuildJsStackTrace(
1141             thread, false, false, ecmascript::JS_STACK_TRACE_DEPTH_MAX);
1142     } else {
1143         ecmascript::ThreadManagedScope runningScope(thread);
1144         ecmascript::SuspendAllScope suspendScope(thread);
1145         auto mainThread = ecmascript::Runtime::GetInstance()->GetMainThread();
1146         stackTraceStr = ecmascript::JsStackInfo::BuildJsStackTrace(
1147             mainThread, false, false, ecmascript::JS_STACK_TRACE_DEPTH_MAX);
1148     }
1149     auto sourceMapcb = vm->GetSourceMapCallback();
1150     if (sourceMapcb != nullptr && !stackTraceStr.empty()) {
1151         stackTraceStr = sourceMapcb(stackTraceStr);
1152     }
1153 }
1154 
SetJsRawHeapCropLevel(CropLevel level)1155 void DFXJSNApi::SetJsRawHeapCropLevel(CropLevel level)
1156 {
1157     // SetJsRawHeapCropLevel
1158     ecmascript::Runtime::GetInstance()->SetRawHeapDumpCropLevel(level);
1159     LOG_ECMA(INFO) << "Set raw heap dump level " << static_cast<int>(level);
1160 }
1161 
FindFunctionForHook(const EcmaVM * vm,const std::string & recordName,const std::string & namespaceName,const std::string & className,const std::string & funcName)1162 JSHandle<JSTaggedValue> DFXJSNApi::FindFunctionForHook(const EcmaVM *vm, const std::string &recordName,
1163                                                        const std::string &namespaceName, const std::string &className,
1164                                                        const std::string &funcName)
1165 {
1166     JSThread *thread = vm->GetJSThread();
1167     return SourceTextModule::FindFuncInModuleForHook(thread, recordName, namespaceName, className, funcName);
1168 }
1169 
ReplaceFunctionForHook(const EcmaVM * vm,JSHandle<JSTaggedValue> & target,JSHandle<JSTaggedValue> & hook,JSHandle<JSTaggedValue> & backup)1170 void DFXJSNApi::ReplaceFunctionForHook(const EcmaVM *vm, JSHandle<JSTaggedValue> &target,
1171                                        JSHandle<JSTaggedValue> &hook, JSHandle<JSTaggedValue> &backup)
1172 {
1173     if (!target->IsJSFunction() || !hook->IsJSFunction() || !backup->IsJSFunction()) {
1174         return;
1175     }
1176 
1177     JSThread *thread = vm->GetJSThread();
1178     JSHandle<JSFunction> targetFunc = JSHandle<JSFunction>::Cast(target);
1179     JSHandle<JSFunction> hookFunc = JSHandle<JSFunction>::Cast(hook);
1180     JSHandle<JSFunction> backupFunc = JSHandle<JSFunction>::Cast(backup);
1181 
1182     JSFunction::ReplaceFunctionForHook(thread, backupFunc, targetFunc);
1183     JSFunction::ReplaceFunctionForHook(thread, targetFunc, hookFunc);
1184 }
1185 
LoadHookModule(const EcmaVM * vm)1186 bool DFXJSNApi::LoadHookModule(const EcmaVM *vm)
1187 {
1188     const CString path(ecmascript::ohos::OhosConstants::HOOK_FILE_PATH);
1189     return JSPandaFileExecutor::ExecuteInsecureAbcFile(vm->GetJSThread(), path);
1190 }
1191 } // namespace panda