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