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 "ark_native_engine.h"
17
18#ifdef ENABLE_HITRACE
19#include <sys/prctl.h>
20#endif
21
22#include <sstream>
23#include "ark_native_deferred.h"
24#if !defined(is_arkui_x) && defined(OHOS_PLATFORM)
25#include "unwinder.h"
26#endif
27#include "ark_native_reference.h"
28#include "native_engine/native_property.h"
29#include "native_engine/native_utils.h"
30#include "native_sendable.h"
31#include "securec.h"
32#include "utils/file.h"
33#include "utils/log.h"
34#if !defined(PREVIEW) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
35#include "parameters.h"
36#include <uv.h>
37#endif
38#ifdef ENABLE_CONTAINER_SCOPE
39#include "core/common/container_scope.h"
40#endif
41#if defined(ENABLE_EVENT_HANDLER)
42#include "event_handler.h"
43#endif
44#ifdef ENABLE_HITRACE
45#include "hitrace/trace.h"
46#include "hitrace_meter.h"
47#include "parameter.h"
48#include "musl_preinit_common.h"
49#include "memory_trace.h"
50
51// LCOV_EXCL_START
52struct alignas(8) HookJsConfig { // 8 is 8 bit
53    int32_t jsStackReport = 0;
54    uint8_t maxJsStackDepth = 0;
55    bool jsFpUnwind = false;
56    char filterNapiName[64] = { "" };
57};
58
59class BlockHookScope {
60public:
61    BlockHookScope()
62    {
63        previousState_ = __set_hook_flag(false);
64    }
65    ~BlockHookScope()
66    {
67        __set_hook_flag(previousState_);
68    }
69private:
70    bool previousState_ {true};
71};
72
73static HookJsConfig* g_hookJsConfig = nullptr;
74static std::once_flag g_hookOnceFlag;
75static std::string JS_CALL_STACK_DEPTH_SEP = ","; // ',' is js call stack depth separator
76static std::string JS_SYMBOL_FILEPATH_SEP = "|";  // '|' is js symbol and filepath separator
77static constexpr uint64_t BUF_SIZE = 128;
78#endif
79
80using panda::JsiRuntimeCallInfo;
81using panda::BooleanRef;
82using panda::ObjectRef;
83using panda::StringRef;
84using panda::Global;
85using panda::JSNApi;
86using panda::FunctionRef;
87using panda::PrimitiveRef;
88using panda::ArrayBufferRef;
89using panda::TypedArrayRef;
90using panda::PromiseCapabilityRef;
91using panda::PropertyAttribute;
92using panda::NativePointerRef;
93using panda::SymbolRef;
94using panda::IntegerRef;
95using panda::DateRef;
96using panda::BigIntRef;
97static constexpr auto PANDA_MAIN_FUNCTION = "_GLOBAL::func_main_0";
98static constexpr auto PANDA_MODULE_NAME = "_GLOBAL_MODULE_NAME";
99static constexpr auto PANDA_MODULE_NAME_LEN = 32;
100static std::unordered_set<std::string> NATIVE_MODULE = {"system.app", "ohos.app", "system.router",
101    "system.curves", "ohos.curves", "system.matrix4", "ohos.matrix4"};
102static constexpr auto NATIVE_MODULE_PREFIX = "@native:";
103static constexpr auto OHOS_MODULE_PREFIX = "@ohos:";
104#ifdef ENABLE_HITRACE
105constexpr auto NAPI_PROFILER_PARAM_SIZE = 10;
106std::atomic<uint64_t> g_chainId = 0;
107constexpr int NAPI_CALL_STACK = 2; // just for napi call stack
108#endif
109
110std::string ArkNativeEngine::tempModuleName_ {""};
111bool ArkNativeEngine::napiProfilerEnabled {false};
112bool ArkNativeEngine::napiProfilerParamReaded {false};
113PermissionCheckCallback ArkNativeEngine::permissionCheckCallback_ {nullptr};
114
115// This interface is using by ace_engine
116napi_value LocalValueToLocalNapiValue(panda::Local<panda::JSValueRef> local)
117{
118    return JsValueFromLocalValue(local);
119}
120
121// This interface is using by ace_engine
122panda::Local<panda::JSValueRef> NapiValueToLocalValue(napi_value v)
123{
124    return LocalValueFromJsValue(v);
125}
126
127#ifdef ENABLE_CONTAINER_SCOPE
128void FunctionSetContainerId(const EcmaVM *vm, panda::Local<panda::JSValueRef> &value)
129{
130    if (!value->IsFunction(vm)) {
131        return;
132    }
133    panda::Local<panda::FunctionRef> funcValue(value);
134    if (funcValue->IsNative(vm)) {
135        return;
136    }
137
138    auto extraInfo = funcValue->GetData(vm);
139    if (extraInfo != nullptr) {
140        return;
141    }
142
143    NapiFunctionInfo *funcInfo = NapiFunctionInfo::CreateNewInstance();
144    if (funcInfo == nullptr) {
145        HILOG_ERROR("funcInfo is nullptr");
146        return;
147    }
148    funcInfo->scopeId = OHOS::Ace::ContainerScope::CurrentId();
149    funcValue->SetData(vm, reinterpret_cast<void*>(funcInfo),
150        [](void* env, void *externalPointer, void *data) {
151            auto info = reinterpret_cast<NapiFunctionInfo*>(data);
152            if (info != nullptr) {
153                delete info;
154                info = nullptr;
155            }
156        }, true);
157}
158#endif
159
160panda::Local<panda::JSValueRef> NapiDefineClass(napi_env env, const char* name, NapiNativeCallback callback,
161    void* data, const NapiPropertyDescriptor* properties, size_t length)
162{
163    auto vm = const_cast<EcmaVM*>(reinterpret_cast<NativeEngine*>(env)->GetEcmaVm());
164    std::string className(name);
165    if (ArkNativeEngine::napiProfilerEnabled) {
166        className = ArkNativeEngine::tempModuleName_ + "." + name;
167    }
168
169    NapiFunctionInfo* funcInfo = NapiFunctionInfo::CreateNewInstance();
170    if (funcInfo == nullptr) {
171        HILOG_ERROR("funcInfo is nullptr");
172        return panda::JSValueRef::Undefined(vm);
173    }
174    funcInfo->callback = callback;
175    funcInfo->data = data;
176#ifdef ENABLE_CONTAINER_SCOPE
177    funcInfo->scopeId = OHOS::Ace::ContainerScope::CurrentId();
178#endif
179
180    Local<panda::FunctionRef> fn = panda::FunctionRef::NewConcurrentClassFunction(vm, ArkNativeFunctionCallBack,
181        [](void* env, void* externalPointer, void* data) {
182            auto info = reinterpret_cast<NapiFunctionInfo*>(data);
183                if (info != nullptr) {
184                    delete info;
185                }
186            },
187        reinterpret_cast<void*>(funcInfo), true);
188
189    Local<panda::StringRef> fnName = panda::StringRef::NewFromUtf8(vm, className.c_str());
190    fn->SetName(vm, fnName);
191
192    if (length == 0) {
193        return fn;
194    }
195    Local<panda::ObjectRef> classPrototype = fn->GetFunctionPrototype(vm);
196    Local<panda::ObjectRef> fnObj = fn->ToObject(vm);
197    for (size_t i = 0; i < length; i++) {
198        if (properties[i].attributes & NATIVE_STATIC) {
199            NapiDefineProperty(env, fnObj, properties[i]);
200        } else {
201            if (classPrototype->IsUndefined()) {
202                HILOG_ERROR("ArkNativeEngineImpl::Class's prototype is null");
203                continue;
204            }
205            reinterpret_cast<ArkNativeEngine*>(env)->SetModuleName(classPrototype, className);
206            NapiDefineProperty(env, classPrototype, properties[i]);
207        }
208    }
209
210    return fn;
211}
212
213Local<panda::JSValueRef> NapiNativeCreateSendableFunction(napi_env env,
214                                                          const char* name,
215                                                          NapiNativeCallback cb,
216                                                          void* value)
217{
218    auto engine = reinterpret_cast<NativeEngine*>(env);
219    auto vm = const_cast<EcmaVM*>(engine->GetEcmaVm());
220    NapiFunctionInfo* funcInfo = NapiFunctionInfo::CreateNewInstance();
221    if (funcInfo == nullptr) {
222        HILOG_ERROR("funcInfo is nullptr");
223        return JSValueRef::Undefined(vm);
224    }
225    funcInfo->callback = cb;
226    funcInfo->data = value;
227
228    Local<panda::FunctionRef> fn = panda::FunctionRef::NewSendable(
229        vm, ArkNativeFunctionCallBack,
230        [](void* env, void* externalPointer, void* data) {
231            auto info = reinterpret_cast<NapiFunctionInfo*>(data);
232            if (info != nullptr) {
233                delete info;
234            }
235        },
236        reinterpret_cast<void*>(funcInfo), true);
237    return fn;
238}
239
240panda::Local<panda::JSValueRef> NapiDefineSendableClass(napi_env env,
241                                                        const char* name,
242                                                        NapiNativeCallback callback,
243                                                        void* data,
244                                                        const NapiPropertyDescriptor* properties,
245                                                        size_t propertiesLength,
246                                                        napi_value parent)
247{
248    const EcmaVM* vm = reinterpret_cast<NativeEngine*>(env)->GetEcmaVm();
249    NapiFunctionInfo* funcInfo = NapiFunctionInfo::CreateNewInstance();
250    if (funcInfo == nullptr) {
251        HILOG_FATAL("funcInfo is nullptr");
252        return JSValueRef::Undefined(vm);
253    }
254    funcInfo->callback = callback;
255    funcInfo->data = data;
256
257    std::string className(name);
258    if (ArkNativeEngine::napiProfilerEnabled) {
259        className = ArkNativeEngine::tempModuleName_ + "." + name;
260    }
261
262    Local<panda::StringRef> fnName = panda::StringRef::NewFromUtf8(vm, className.c_str());
263    Local<JSValueRef> localParent = JSValueRef::Null(vm);
264    if (parent != nullptr) {
265        localParent = LocalValueFromJsValue(parent);
266    }
267
268    auto infos = NativeSendable::CreateSendablePropertiesInfos(env, properties, propertiesLength);
269    Local<panda::FunctionRef> fn = panda::FunctionRef::NewSendableClassFunction(
270        vm, ArkNativeFunctionCallBack,
271        [](void* env, void* externalPointer, void* data) {
272            auto info = reinterpret_cast<NapiFunctionInfo*>(data);
273            if (info != nullptr) {
274                delete info;
275            }
276        },
277        reinterpret_cast<void*>(funcInfo), fnName, infos, localParent, true);
278
279    return fn;
280}
281
282struct MoudleNameLocker {
283    explicit MoudleNameLocker(std::string moduleName)
284    {
285        ArkNativeEngine::tempModuleName_ = moduleName;
286    }
287    ~MoudleNameLocker()
288    {
289        ArkNativeEngine::tempModuleName_ = "";
290    }
291};
292
293void* ArkNativeEngine::GetNativePtrCallBack(void* data)
294{
295    if (data == nullptr) {
296        HILOG_ERROR("data is nullptr");
297        return nullptr;
298    }
299    auto info = reinterpret_cast<NapiFunctionInfo*>(data);
300    auto cb = reinterpret_cast<void*>(info->callback);
301    return cb;
302}
303
304bool ArkNativeEngine::CheckArkApiAllowList(
305    NativeModule* module, panda::ecmascript::ApiCheckContext context, panda::Local<panda::ObjectRef>& exportCopy)
306{
307    std::unique_ptr<ApiAllowListChecker>& apiAllowListChecker = module->apiAllowListChecker;
308    if (apiAllowListChecker != nullptr) {
309        const std::string apiPath = context.moduleName->ToString(context.ecmaVm);
310        if ((*apiAllowListChecker)(apiPath)) {
311            CopyPropertyApiFilter(apiAllowListChecker, context.ecmaVm, context.exportObj, exportCopy, apiPath);
312        }
313        return true;
314    }
315    return false;
316}
317
318void ArkNativeEngine::CopyPropertyApiFilter(const std::unique_ptr<ApiAllowListChecker>& apiAllowListChecker,
319    const EcmaVM* ecmaVm, const panda::Local<panda::ObjectRef> exportObj, panda::Local<panda::ObjectRef>& exportCopy,
320    const std::string& apiPath)
321{
322    panda::Local<panda::ArrayRef> namesArrayRef = exportObj->GetAllPropertyNames(ecmaVm, NATIVE_DEFAULT);
323    for (uint32_t i = 0; i < namesArrayRef->Length(ecmaVm); ++i) {
324        const panda::Local<panda::JSValueRef> nameValue = panda::ArrayRef::GetValueAt(ecmaVm, namesArrayRef, i);
325        const panda::Local<panda::JSValueRef> value = exportObj->Get(ecmaVm, nameValue);
326        const std::string curPath = apiPath + "." + nameValue->ToString(ecmaVm)->ToString(ecmaVm);
327        if ((*apiAllowListChecker)(curPath)) {
328            const std::string valueType = value->Typeof(ecmaVm)->ToString(ecmaVm);
329            if (valueType == "object") {
330                panda::Local<panda::ObjectRef> subObject = ObjectRef::New(ecmaVm);
331                CopyPropertyApiFilter(apiAllowListChecker, ecmaVm, value, subObject, curPath);
332                exportCopy->Set(ecmaVm, nameValue, subObject);
333                HILOG_DEBUG("Set the package '%{public}s' to the allow list", curPath.c_str());
334            } else if (valueType == "function") {
335                exportCopy->Set(ecmaVm, nameValue, value);
336                HILOG_DEBUG("Set the function '%{public}s' to the allow list", curPath.c_str());
337            } else {
338                exportCopy->Set(ecmaVm, nameValue, value);
339                HILOG_DEBUG("Set the element type is '%{public}s::%{public}s' to the allow list", valueType.c_str(),
340                    curPath.c_str());
341            }
342        }
343    }
344}
345
346ArkNativeEngine::ArkNativeEngine(EcmaVM* vm, void* jsEngine, bool isLimitedWorker) : NativeEngine(jsEngine, vm),
347                                                                                     topScope_(vm),
348                                                                                     isLimitedWorker_(isLimitedWorker)
349{
350    HILOG_DEBUG("ArkNativeEngine::ArkNativeEngine");
351    panda::JSNApi::SetEnv(vm, this);
352#ifdef ENABLE_HITRACE
353    if (!ArkNativeEngine::napiProfilerParamReaded) {
354        char napiProfilerParam[NAPI_PROFILER_PARAM_SIZE] = {0};
355        int ret = GetParameter("persist.hiviewdfx.napiprofiler.enabled", "false",
356            napiProfilerParam, sizeof(napiProfilerParam));
357        if (ret > 0 && strcmp(napiProfilerParam, "true") == 0) {
358            ArkNativeEngine::napiProfilerEnabled = true;
359        }
360        ArkNativeEngine::napiProfilerParamReaded = true;
361    }
362#endif
363    LocalScope scope(vm_);
364    Local<StringRef> requireInternalName = StringRef::NewFromUtf8(vm, "requireInternal");
365    void* requireData = static_cast<void*>(this);
366
367    options_ = new NapiOptions();
368    crossThreadCheck_ = JSNApi::IsMultiThreadCheckEnabled(vm);
369#if defined(OHOS_PLATFORM) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
370    int napiProperties = OHOS::system::GetIntParameter<int>("persist.ark.napi.properties", -1);
371    if (options_ != nullptr) {
372        options_->SetProperties(napiProperties);
373    }
374#endif
375    Local<FunctionRef> requireNapi =
376        FunctionRef::New(
377            vm,
378            [](JsiRuntimeCallInfo *info) -> Local<JSValueRef> {
379                EcmaVM *ecmaVm = info->GetVM();
380                panda::EscapeLocalScope scope(ecmaVm);
381                NativeModuleManager* moduleManager = NativeModuleManager::GetInstance();
382                ArkNativeEngine* arkNativeEngine = static_cast<ArkNativeEngine*>(info->GetData());
383                Local<StringRef> moduleName(info->GetCallArgRef(0));
384                NativeModule* module = nullptr;
385                bool isAppModule = false;
386                std::string errInfo = "";
387                Local<JSValueRef> exports(JSValueRef::Undefined(ecmaVm));
388#ifdef IOS_PLATFORM
389                if (arkNativeEngine->isLimitedWorker_) {
390                    if (!moduleManager->CheckModuleRestricted(moduleName->ToString(ecmaVm).c_str())) {
391                        HILOG_ERROR("module %{public}s does not found in whitelist",
392                            moduleName->ToString(ecmaVm).c_str());
393                        return scope.Escape(exports);
394                    }
395                }
396                module = moduleManager->LoadNativeModule(
397                    moduleName->ToString(ecmaVm).c_str(), nullptr, false, errInfo, false, "");
398#else
399                const uint32_t lengthMax = 2;
400                if (info->GetArgsNumber() >= lengthMax) {
401                    Local<BooleanRef> ret(info->GetCallArgRef(1));
402                    isAppModule = ret->Value();
403                }
404                arkNativeEngine->isAppModule_ = isAppModule;
405                if (arkNativeEngine->isLimitedWorker_ && !isAppModule) {
406                    if (!moduleManager->CheckModuleRestricted(moduleName->ToString(ecmaVm).c_str())) {
407                        HILOG_ERROR("module %{public}s does not found in whitelist",
408                            moduleName->ToString(ecmaVm).c_str());
409                        return scope.Escape(exports);
410                    }
411                }
412
413                if (info->GetArgsNumber() == 3) { // 3:Determine if the number of parameters is equal to 3
414                    Local<StringRef> path(info->GetCallArgRef(2)); // 2:Take the second parameter
415                    module = moduleManager->LoadNativeModule(moduleName->ToString(ecmaVm).c_str(),
416                        path->ToString(ecmaVm).c_str(), isAppModule, errInfo, false, "");
417                } else if (info->GetArgsNumber() == 4) { // 4:Determine if the number of parameters is equal to 4
418                    Local<StringRef> path(info->GetCallArgRef(2)); // 2:Take the second parameter
419                    Local<StringRef> relativePath(info->GetCallArgRef(3)); // 3:Take the second parameter
420                    module = moduleManager->LoadNativeModule(moduleName->ToString(ecmaVm).c_str(), nullptr, isAppModule,
421                        errInfo, false, relativePath->ToString(ecmaVm).c_str());
422                } else {
423                    module =
424                        moduleManager->LoadNativeModule(moduleName->ToString(ecmaVm).c_str(),
425                        nullptr, isAppModule, errInfo, false, "");
426                }
427#endif
428                if (module != nullptr) {
429                    auto it = arkNativeEngine->loadedModules_.find(module);
430                    if (it != arkNativeEngine->loadedModules_.end()) {
431                        return scope.Escape(it->second.ToLocal(ecmaVm));
432                    }
433                    std::string strModuleName = moduleName->ToString(ecmaVm);
434                    moduleManager->SetNativeEngine(strModuleName, arkNativeEngine);
435                    MoudleNameLocker nameLocker(strModuleName);
436
437                    if (module->jsCode == nullptr && module->getABCCode != nullptr) {
438                        module->getABCCode(&module->jsCode, &module->jsCodeLen);
439                    }
440                    if (module->jsABCCode != nullptr || module->jsCode != nullptr) {
441                        char fileName[NAPI_PATH_MAX] = { 0 };
442                        const char* name = module->name;
443                        if (sprintf_s(fileName, sizeof(fileName), "lib%s.z.so/%s.js", name, name) == -1) {
444                            HILOG_ERROR("sprintf_s file name failed");
445                            return scope.Escape(exports);
446                        }
447                        HILOG_DEBUG("load js code from %{public}s", fileName);
448                        const void *buffer = nullptr;
449                        if (module->jsABCCode) {
450                            buffer = static_cast<const void *>(module->jsABCCode);
451                        } else {
452                            buffer = static_cast<const void *>(module->jsCode);
453                        }
454                        auto exportObject = arkNativeEngine->LoadArkModule(buffer, module->jsCodeLen, fileName);
455                        if (exportObject->IsUndefined()) {
456                            HILOG_ERROR("load module failed");
457                            return scope.Escape(exports);
458                        } else {
459                            exports = exportObject;
460                            arkNativeEngine->loadedModules_[module] = Global<JSValueRef>(ecmaVm, exports);
461                        }
462                    } else if (module->registerCallback != nullptr) {
463                        Local<ObjectRef> exportObj = ObjectRef::New(ecmaVm);
464#ifdef ENABLE_HITRACE
465                        StartTrace(HITRACE_TAG_ACE, "NAPI module init, name = " + std::string(module->name));
466#endif
467                        arkNativeEngine->SetModuleName(exportObj, module->name);
468                        module->registerCallback(reinterpret_cast<napi_env>(arkNativeEngine),
469                                                 JsValueFromLocalValue(exportObj));
470#ifdef ENABLE_HITRACE
471                        FinishTrace(HITRACE_TAG_ACE);
472#endif
473                        panda::Local<panda::ObjectRef> exportCopy = panda::ObjectRef::New(ecmaVm);
474                        panda::ecmascript::ApiCheckContext context{moduleManager, ecmaVm, moduleName, exportObj, scope};
475                        if (CheckArkApiAllowList(module, context, exportCopy)) {
476                            return scope.Escape(exportCopy);
477                        }
478                        exports = exportObj;
479                        arkNativeEngine->loadedModules_[module] = Global<JSValueRef>(ecmaVm, exports);
480                    } else {
481                        HILOG_ERROR("init module failed");
482                        return scope.Escape(exports);
483                    }
484                }
485                if (module == nullptr) {
486                    HILOG_INFO("%{public}s", errInfo.c_str());
487                    exports = panda::ObjectRef::CreateNativeModuleFailureInfo(ecmaVm, errInfo);
488                }
489                return scope.Escape(exports);
490            },
491            nullptr,
492            requireData);
493
494    Local<FunctionRef> requireInternal =
495        FunctionRef::New(
496            vm,
497            [](JsiRuntimeCallInfo *info) -> Local<JSValueRef> {
498                EcmaVM *ecmaVm = info->GetVM();
499                panda::EscapeLocalScope scope(ecmaVm);
500                NativeModuleManager* moduleManager = NativeModuleManager::GetInstance();
501                ArkNativeEngine* arkNativeEngine = static_cast<ArkNativeEngine*>(info->GetData());
502                Local<StringRef> moduleName(info->GetCallArgRef(0));
503                std::string errInfo = "";
504                Local<JSValueRef> exports(JSValueRef::Undefined(ecmaVm));
505                if (arkNativeEngine->isLimitedWorker_) {
506                    if (!moduleManager->CheckModuleRestricted(moduleName->ToString(ecmaVm).c_str())) {
507                        HILOG_ERROR("module %{public}s does not found in whitelist",
508                            moduleName->ToString(ecmaVm).c_str());
509                        return scope.Escape(exports);
510                    }
511                }
512                NativeModule* module = moduleManager->LoadNativeModule(moduleName->ToString(ecmaVm).c_str(),
513                    nullptr, false, errInfo, false, "");
514                MoudleNameLocker nameLocker(moduleName->ToString(ecmaVm));
515                if (module != nullptr && arkNativeEngine) {
516                    auto it = arkNativeEngine->loadedModules_.find(module);
517                    if (it != arkNativeEngine->loadedModules_.end()) {
518                        return scope.Escape(it->second.ToLocal(ecmaVm));
519                    }
520                    std::string strModuleName = moduleName->ToString(ecmaVm);
521                    moduleManager->SetNativeEngine(strModuleName, arkNativeEngine);
522                    Local<ObjectRef> exportObj = ObjectRef::New(ecmaVm);
523                    if (exportObj->IsObject(ecmaVm)) {
524                        arkNativeEngine->SetModuleName(exportObj, module->name);
525                        module->registerCallback(reinterpret_cast<napi_env>(arkNativeEngine),
526                                                 JsValueFromLocalValue(exportObj));
527                        exports = exportObj;
528                        arkNativeEngine->loadedModules_[module] = Global<JSValueRef>(ecmaVm, exports);
529                    } else {
530                        HILOG_ERROR("exportObject is nullptr");
531                        return scope.Escape(exports);
532                    }
533                }
534                return scope.Escape(exports);
535            },
536            nullptr,
537            requireData);
538
539    Local<ObjectRef> global = panda::JSNApi::GetGlobalObject(vm);
540#if !defined(PREVIEW)
541    Local<StringRef> requireName = StringRef::NewFromUtf8(vm, "requireNapi");
542    global->Set(vm, requireName, requireNapi);
543#else
544    Local<StringRef> requireNapiPreview = StringRef::NewFromUtf8(vm, "requireNapiPreview");
545    global->Set(vm, requireNapiPreview, requireNapi);
546#endif
547    global->Set(vm, requireInternalName, requireInternal);
548    JSNApi::SetNativePtrGetter(vm, reinterpret_cast<void*>(ArkNativeEngine::GetNativePtrCallBack));
549    // need to call init of base class.
550    NativeModuleManager* moduleManager = NativeModuleManager::GetInstance();
551    std::function<bool(const std::string&)> func = [moduleManager](const std::string& moduleKey) -> bool {
552        return moduleManager->UnloadNativeModule(moduleKey);
553    };
554    JSNApi::SetUnloadNativeModuleCallback(vm, func);
555    Init();
556    panda::JSNApi::SetLoop(vm, loop_);
557    panda::JSNApi::SetWeakFinalizeTaskCallback(vm, [this] () -> void {
558        this->PostFinalizeTasks();
559    });
560    JSNApi::SetAsyncCleanTaskCallback(vm, [this] (AsyncNativeCallbacksPack *callbacksPack) {
561        this->PostAsyncTask(callbacksPack);
562    });
563#if defined(ENABLE_EVENT_HANDLER)
564    if (JSNApi::IsJSMainThreadOfEcmaVM(vm)) {
565        arkIdleMonitor_ = new ArkIdleMonitor(vm);
566        JSNApi::SetTriggerGCTaskCallback(vm, [this](TriggerGCData& data) {
567            this->PostTriggerGCTask(data);
568        });
569        arkIdleMonitor_->SetStartTimerCallback();
570        PostLooperTriggerIdleGCTask();
571    }
572#endif
573}
574
575ArkNativeEngine::~ArkNativeEngine()
576{
577    HILOG_DEBUG("ArkNativeEngine::~ArkNativeEngine");
578    Deinit();
579    // Free cached objects
580    for (auto&& [module, exportObj] : loadedModules_) {
581        exportObj.FreeGlobalHandleAddr();
582    }
583    // Free callbackRef
584    if (promiseRejectCallbackRef_ != nullptr) {
585        delete promiseRejectCallbackRef_;
586    }
587    if (checkCallbackRef_ != nullptr) {
588        delete checkCallbackRef_;
589    }
590    if (options_ != nullptr) {
591        delete options_;
592        options_ = nullptr;
593    }
594
595    if (arkIdleMonitor_ != nullptr) {
596        delete arkIdleMonitor_;
597        arkIdleMonitor_ = nullptr;
598    }
599}
600
601#ifdef ENABLE_HITRACE
602static inline bool CheckHookConfig(const std::string &nameRef)
603{
604    if (g_hookJsConfig == nullptr || g_hookJsConfig->jsStackReport <= 0 ||
605        g_hookJsConfig->maxJsStackDepth == 0 || !g_hookJsConfig->jsFpUnwind) {
606        return false;
607    } else if (g_hookJsConfig->filterNapiName[0] != '\0' &&
608        nameRef.find(g_hookJsConfig->filterNapiName) != std::string::npos) {
609        return false;
610    }
611    return true;
612}
613#endif
614
615static inline uint64_t StartNapiProfilerTrace(panda::JsiRuntimeCallInfo* runtimeInfo, void* cb)
616{
617#ifdef ENABLE_HITRACE
618    if (ArkNativeEngine::napiProfilerEnabled) {
619        EcmaVM *vm = runtimeInfo->GetVM();
620        LocalScope scope(vm);
621        Local<panda::FunctionRef> fn = runtimeInfo->GetFunctionRef();
622        Local<panda::StringRef> nameRef = fn->GetName(vm);
623        char threadName[BUF_SIZE];
624        prctl(PR_GET_NAME, threadName);
625        StartTraceArgs(HITRACE_TAG_ACE, "Napi called:%s, tname:%s", nameRef->ToString(vm).c_str(), threadName);
626    }
627    bool hookFlag = __get_hook_flag() && __get_global_hook_flag();
628    if (!hookFlag) {
629        return 0;
630    }
631    EcmaVM* vm = runtimeInfo->GetVM();
632    LocalScope scope(vm);
633    Local<panda::FunctionRef> fn = runtimeInfo->GetFunctionRef();
634    Local<panda::StringRef> nameRef = fn->GetName(vm);
635    if (g_hookJsConfig == nullptr) {
636        std::call_once(g_hookOnceFlag, []() { g_hookJsConfig = (HookJsConfig*)__get_hook_config(); });
637    }
638    // add memtrace function
639    if (g_hookJsConfig != nullptr && g_hookJsConfig->jsStackReport == NAPI_CALL_STACK && !g_hookJsConfig->jsFpUnwind) {
640        OHOS::HiviewDFX::HiTraceChain::ClearId();
641        std::unique_ptr<OHOS::HiviewDFX::HiTraceId> arkCallBackTraceId = std::make_unique<OHOS::HiviewDFX::HiTraceId>(
642            OHOS::HiviewDFX::HiTraceChain::Begin("New ArkCallBackTrace", 0));
643        char buffer[256] = {0}; // 256 : buffer size of tag name
644        if (sprintf_s(buffer, sizeof(buffer), "napi:0x%x:%s", arkCallBackTraceId->GetChainId(),
645                      nameRef->ToString(vm).c_str()) == -1) {
646            return 0;
647        }
648        uint64_t addr = reinterpret_cast<uint64_t>(cb);
649        ++g_chainId;
650        (void)memtrace(reinterpret_cast<void*>(addr + g_chainId), 8, buffer, true); // 8: the size of addr
651        return 0;
652    }
653    if (!CheckHookConfig(nameRef->ToString(vm))) {
654        return 0;
655    }
656    BlockHookScope blockHook; // block hook
657    std::string rawStack;
658    std::vector<JsFrameInfo> jsFrames;
659    uint64_t nestChainId = 0;
660    jsFrames.reserve(g_hookJsConfig->maxJsStackDepth);
661    auto env = reinterpret_cast<napi_env>(JSNApi::GetEnv(vm));
662    auto engine = reinterpret_cast<NativeEngine*>(env);
663    engine->BuildJsStackInfoListWithCustomDepth(jsFrames);
664    std::stringstream ssRawStack;
665    for (size_t i = 0; i < jsFrames.size() && i < g_hookJsConfig->maxJsStackDepth; i++) {
666        ssRawStack << jsFrames[i].functionName << JS_SYMBOL_FILEPATH_SEP << jsFrames[i].fileName << ":" <<
667            jsFrames[i].pos;
668        if (i < jsFrames.size() - 1) {
669            ssRawStack << JS_CALL_STACK_DEPTH_SEP;
670        }
671    }
672    rawStack = ssRawStack.str();
673    OHOS::HiviewDFX::HiTraceChain::Begin("ArkNativeFunctionCallBack", 0);
674    OHOS::HiviewDFX::HiTraceId hitraceId = OHOS::HiviewDFX::HiTraceChain::GetId();
675    // resolve nested calls to napi and ts
676    if (hitraceId.IsValid()) {
677        nestChainId = hitraceId.GetChainId();
678    }
679    uint64_t chainId = ++g_chainId;
680    hitraceId.SetChainId(chainId);
681    OHOS::HiviewDFX::HiTraceChain::SetId(hitraceId);
682    __send_hook_misc_data(chainId, rawStack.c_str(), rawStack.size() + 1, 1);
683    return nestChainId;
684
685#endif
686    return 0;
687}
688
689static inline void FinishNapiProfilerTrace(uint64_t value)
690{
691#ifdef ENABLE_HITRACE
692    if (ArkNativeEngine::napiProfilerEnabled) {
693        FinishTrace(HITRACE_TAG_ACE);
694    }
695    bool hookFlag = __get_hook_flag() && __get_global_hook_flag();
696    if (!hookFlag) {
697        return;
698    }
699    BlockHookScope blockHook; // block hook
700    OHOS::HiviewDFX::HiTraceId hitraceId = OHOS::HiviewDFX::HiTraceChain::GetId();
701    if (hitraceId.IsValid()) {
702        OHOS::HiviewDFX::HiTraceChain::End(hitraceId);
703        OHOS::HiviewDFX::HiTraceChain::ClearId();
704    }
705    // resolve nested calls to napi and ts
706    if (value) {
707        hitraceId.SetChainId(value);
708        OHOS::HiviewDFX::HiTraceChain::SetId(hitraceId);
709    }
710
711#endif
712}
713
714template <bool changeState>
715panda::JSValueRef ArkNativeFunctionCallBack(JsiRuntimeCallInfo *runtimeInfo)
716{
717    EcmaVM *vm = runtimeInfo->GetVM();
718    panda::LocalScope scope(vm);
719    bool getStackBeforeCallNapiSuccess = false;
720    JSNApi::GetStackBeforeCallNapiSuccess(vm, getStackBeforeCallNapiSuccess);
721    auto info = reinterpret_cast<NapiFunctionInfo*>(runtimeInfo->GetData());
722    auto env = reinterpret_cast<napi_env>(JSNApi::GetEnv(vm));
723    auto engine = reinterpret_cast<NativeEngine*>(env);
724    auto cb = info->callback;
725    if (engine == nullptr) {
726        HILOG_ERROR("native engine is null");
727        return **JSValueRef::Undefined(vm);
728    }
729
730    uint64_t nestChainId = StartNapiProfilerTrace(runtimeInfo, reinterpret_cast<void *>(cb));
731
732    if (JSNApi::IsMixedDebugEnabled(vm)) {
733        JSNApi::NotifyNativeCalling(vm, reinterpret_cast<void *>(cb));
734    }
735
736    napi_value result = nullptr;
737    if (cb != nullptr) {
738        if constexpr (changeState) {
739            panda::JsiNativeScope nativeScope(vm);
740            result = cb(env, runtimeInfo);
741        } else {
742            result = cb(env, runtimeInfo);
743        }
744    }
745
746    if (JSNApi::IsMixedDebugEnabled(vm)) {
747        JSNApi::NotifyNativeReturn(vm, reinterpret_cast<void *>(cb));
748    }
749
750    Local<panda::JSValueRef> localRet = panda::JSValueRef::Undefined(vm);
751    if (result != nullptr) {
752        localRet = LocalValueFromJsValue(result);
753    }
754
755    FinishNapiProfilerTrace(nestChainId);
756    // Fixme: Rethrow error to engine while clear lastException_
757    if (!engine->lastException_.IsEmpty()) {
758        engine->lastException_.Empty();
759    }
760
761    if (localRet.IsEmpty()) {
762        return **JSValueRef::Undefined(vm);
763    }
764    if (getStackBeforeCallNapiSuccess) {
765        JSNApi::GetStackAfterCallNapi(vm);
766    }
767    return **localRet;
768}
769
770static Local<panda::JSValueRef> NapiNativeCreateFunction(napi_env env, const char* name,
771                                                         NapiNativeCallback cb, void* value)
772{
773    auto engine = reinterpret_cast<NativeEngine*>(env);
774    auto vm = const_cast<EcmaVM*>(engine->GetEcmaVm());
775    NapiFunctionInfo* funcInfo = NapiFunctionInfo::CreateNewInstance();
776    if (funcInfo == nullptr) {
777        HILOG_ERROR("funcInfo is nullptr");
778        return JSValueRef::Undefined(vm);
779    }
780    funcInfo->callback = cb;
781    funcInfo->data = value;
782#ifdef ENABLE_CONTAINER_SCOPE
783    funcInfo->scopeId = OHOS::Ace::ContainerScope::CurrentId();
784#endif
785
786    Local<panda::FunctionRef> fn = panda::FunctionRef::NewConcurrent(
787        vm, ArkNativeFunctionCallBack,
788        [](void* env, void* externalPointer, void* data) {
789            auto info = reinterpret_cast<NapiFunctionInfo*>(data);
790            if (info != nullptr) {
791                delete info;
792            }
793        },
794        reinterpret_cast<void*>(funcInfo), true
795    );
796    Local<panda::StringRef> fnName = panda::StringRef::NewFromUtf8(vm, name);
797    fn->SetName(vm, fnName);
798    return fn;
799}
800
801static Local<JSValueRef> GetProperty(EcmaVM* vm, Local<panda::ObjectRef> &obj, const char* name)
802{
803    Local<StringRef> key = StringRef::NewFromUtf8(vm, name);
804    Local<JSValueRef> val = obj->Get(vm, key);
805    return val;
806}
807
808void GetCString(EcmaVM* vm, Local<StringRef> str, char* buffer, size_t size, size_t* length)
809{
810    if (length == nullptr) {
811        return;
812    }
813    if (buffer == nullptr) {
814        *length = str->Utf8Length(vm, true) - 1;
815    } else if (size != 0) {
816        uint32_t copied = str->WriteUtf8(vm, buffer, size - 1, true) - 1;
817        buffer[copied] = '\0';
818        *length = copied;
819    } else {
820        *length = 0;
821    }
822}
823
824std::string NapiGetModuleName(napi_env env, Local<panda::ObjectRef> &obj)
825{
826    auto engine = reinterpret_cast<NativeEngine*>(env);
827    auto vm = const_cast<EcmaVM*>(engine->GetEcmaVm());
828    std::string moduleName("");
829    auto nativeModuleName = GetProperty(vm, obj, PANDA_MODULE_NAME);
830    if (nativeModuleName->IsString(vm)) {
831        char arrayName[PANDA_MODULE_NAME_LEN] = {0};
832        size_t len = 0;
833        GetCString(vm, nativeModuleName, arrayName, PANDA_MODULE_NAME_LEN, &len);
834        moduleName += arrayName;
835        moduleName += ".";
836    }
837    return moduleName;
838}
839
840void NapiDefinePropertyInner(napi_env env,
841                             Local<panda::ObjectRef> &obj,
842                             NapiPropertyDescriptor &propertyDescriptor,
843                             Local<panda::JSValueRef> &propertyName,
844                             bool &result)
845{
846    auto engine = reinterpret_cast<NativeEngine*>(env);
847    auto vm = engine->GetEcmaVm();
848    bool writable = (propertyDescriptor.attributes & NATIVE_WRITABLE) != 0;
849    bool enumable = (propertyDescriptor.attributes & NATIVE_ENUMERABLE) != 0;
850    bool configable = (propertyDescriptor.attributes & NATIVE_CONFIGURABLE) != 0;
851    std::string fullName("");
852    if (propertyDescriptor.getter != nullptr || propertyDescriptor.setter != nullptr) {
853#ifdef ENABLE_HITRACE
854        fullName += NapiGetModuleName(env, obj);
855#endif
856        Local<panda::JSValueRef> localGetter = panda::JSValueRef::Undefined(vm);
857        Local<panda::JSValueRef> localSetter = panda::JSValueRef::Undefined(vm);
858
859        if (propertyDescriptor.getter != nullptr) {
860            fullName += "getter";
861            localGetter = NapiNativeCreateFunction(env, fullName.c_str(),
862                                                   propertyDescriptor.getter, propertyDescriptor.data);
863        }
864        if (propertyDescriptor.setter != nullptr) {
865            fullName += "setter";
866            localSetter = NapiNativeCreateFunction(env, fullName.c_str(),
867                                                   propertyDescriptor.setter, propertyDescriptor.data);
868        }
869
870        PropertyAttribute attr(panda::JSValueRef::Undefined(vm), false, enumable, configable);
871        result = obj->SetAccessorProperty(vm, propertyName, localGetter, localSetter, attr);
872    } else if (propertyDescriptor.method != nullptr) {
873#ifdef ENABLE_HITRACE
874        fullName += NapiGetModuleName(env, obj);
875#endif
876        if (propertyDescriptor.utf8name != nullptr) {
877            fullName += propertyDescriptor.utf8name;
878        } else {
879            fullName += propertyName->IsString(vm)
880                        ? Local<panda::StringRef>(propertyName)->ToString(vm)
881                        : Local<panda::SymbolRef>(propertyName)->GetDescription(vm)->ToString(vm);
882        }
883        Local<panda::JSValueRef> cbObj = NapiNativeCreateFunction(env, fullName.c_str(),
884                                                                  propertyDescriptor.method, propertyDescriptor.data);
885        PropertyAttribute attr(cbObj, writable, enumable, configable);
886        result = obj->DefineProperty(vm, propertyName, attr);
887    } else {
888        Local<panda::JSValueRef> val = LocalValueFromJsValue(propertyDescriptor.value);
889
890        PropertyAttribute attr(val, writable, enumable, configable);
891        result = obj->DefineProperty(vm, propertyName, attr);
892    }
893}
894
895bool NapiDefineProperty(napi_env env, Local<panda::ObjectRef> &obj, NapiPropertyDescriptor propertyDescriptor)
896{
897    auto engine = reinterpret_cast<NativeEngine*>(env);
898    auto vm = engine->GetEcmaVm();
899    bool result = false;
900    Local<panda::JSValueRef> propertyName;
901    if (propertyDescriptor.utf8name != nullptr) {
902        propertyName = panda::StringRef::NewFromUtf8(vm, propertyDescriptor.utf8name);
903    } else {
904        propertyName = LocalValueFromJsValue(propertyDescriptor.name);
905    }
906    if (obj->IsJSShared(vm)) {
907        NativeSendable::NapiDefineSendabledProperty(env, obj, propertyDescriptor, propertyName, result);
908    } else {
909        NapiDefinePropertyInner(env, obj, propertyDescriptor, propertyName, result);
910    }
911    Local<panda::ObjectRef> excep = panda::JSNApi::GetUncaughtException(vm);
912    if (!excep.IsNull()) {
913        HILOG_DEBUG("ArkNativeObject::DefineProperty occur Exception");
914        panda::JSNApi::GetAndClearUncaughtException(vm);
915    }
916    return result;
917}
918
919panda::Local<panda::ObjectRef> NapiCreateObjectWithProperties(napi_env env, size_t propertyCount,
920                                                              const napi_property_descriptor *properties,
921                                                              Local<panda::JSValueRef> *keys,
922                                                              PropertyAttribute *attrs)
923{
924    auto vm = reinterpret_cast<NativeEngine*>(env)->GetEcmaVm();
925    panda::EscapeLocalScope scope(vm);
926    for (size_t i = 0; i < propertyCount; ++i) {
927        const napi_property_descriptor &property = properties[i];
928
929        const char* utf8name = property.utf8name;
930        uint32_t attributes = property.attributes;
931        bool writable = (attributes & NATIVE_WRITABLE) != 0;
932        bool enumable = (attributes & NATIVE_ENUMERABLE) != 0;
933        bool configable = (attributes & NATIVE_CONFIGURABLE) != 0;
934        NapiNativeCallback method = reinterpret_cast<NapiNativeCallback>(property.method);
935        NapiNativeCallback getter = reinterpret_cast<NapiNativeCallback>(property.getter);
936        NapiNativeCallback setter = reinterpret_cast<NapiNativeCallback>(property.setter);
937        napi_value value = property.value;
938        void *data = property.data;
939
940        Local<panda::JSValueRef> val = panda::JSValueRef::Undefined(vm);
941
942        std::string fullName("");
943        if (getter != nullptr || setter != nullptr) {
944            Local<panda::JSValueRef> localGetter = panda::JSValueRef::Undefined(vm);
945            Local<panda::JSValueRef> localSetter = panda::JSValueRef::Undefined(vm);
946
947            if (getter != nullptr) {
948                fullName += "getter";
949                localGetter = NapiNativeCreateFunction(env, fullName.c_str(), getter, data);
950            }
951            if (setter != nullptr) {
952                fullName += "setter";
953                localSetter = NapiNativeCreateFunction(env, fullName.c_str(), setter, data);
954            }
955
956            val = panda::ObjectRef::CreateAccessorData(vm, localGetter, localSetter);
957            writable = false;
958        } else if (method != nullptr) {
959            fullName += utf8name;
960            val = NapiNativeCreateFunction(env, fullName.c_str(), method, data);
961        } else {
962            val = LocalValueFromJsValue(value);
963        }
964        new (reinterpret_cast<void *>(&attrs[i])) PropertyAttribute(val, writable, enumable, configable);
965        keys[i] = panda::StringRef::NewFromUtf8(vm, utf8name);
966    }
967    Local<panda::ObjectRef> object = panda::ObjectRef::NewWithProperties(vm, propertyCount, keys, attrs);
968    return scope.Escape(object);
969}
970
971panda::Local<panda::ObjectRef> NapiCreateSObjectWithProperties(napi_env env,
972                                                               size_t propertyCount,
973                                                               const NapiPropertyDescriptor* properties)
974{
975    auto vm = reinterpret_cast<NativeEngine*>(env)->GetEcmaVm();
976    panda::EscapeLocalScope scope(vm);
977    FunctionRef::SendablePropertiesInfo info;
978    for (size_t i = 0; i < propertyCount; ++i) {
979        NativeSendable::InitSendablePropertiesInfo(env, info, properties[i]);
980    }
981    Local<panda::ObjectRef> object = panda::ObjectRef::NewSWithProperties(vm, info);
982    return scope.Escape(object);
983}
984
985panda::Local<panda::ObjectRef> ArkNativeEngine::GetModuleFromName(
986    const std::string& moduleName, bool isAppModule, const std::string& id, const std::string& param,
987    const std::string& instanceName, void** instance)
988{
989    panda::EscapeLocalScope scope(vm_);
990    Local<ObjectRef> exports(JSValueRef::Undefined(vm_));
991    NativeModuleManager* moduleManager = NativeModuleManager::GetInstance();
992    std::string errInfo = "";
993    NativeModule* module = moduleManager->LoadNativeModule(moduleName.c_str(), nullptr, isAppModule, errInfo);
994    if (module != nullptr) {
995        Local<StringRef> idStr = StringRef::NewFromUtf8(vm_, id.c_str(), id.size());
996        napi_value idValue = JsValueFromLocalValue(idStr);
997        Local<StringRef> paramStr = StringRef::NewFromUtf8(vm_, param.c_str(), param.size());
998        napi_value paramValue = JsValueFromLocalValue(paramStr);
999        Local<ObjectRef> exportObj = ObjectRef::New(vm_);
1000        NapiPropertyDescriptor idProperty, paramProperty;
1001        idProperty.utf8name = "id";
1002        idProperty.value = idValue;
1003        paramProperty.utf8name = "param";
1004        paramProperty.value = paramValue;
1005        SetModuleName(exportObj, module->name);
1006        NapiDefineProperty(reinterpret_cast<napi_env>(this), exportObj, idProperty);
1007        NapiDefineProperty(reinterpret_cast<napi_env>(this), exportObj, paramProperty);
1008        MoudleNameLocker nameLocker(module->name);
1009        module->registerCallback(reinterpret_cast<napi_env>(this), JsValueFromLocalValue(exportObj));
1010        napi_value nExport = JsValueFromLocalValue(exportObj);
1011        napi_value exportInstance = nullptr;
1012        napi_status status = napi_get_named_property(
1013            reinterpret_cast<napi_env>(this), nExport, instanceName.c_str(), &exportInstance);
1014        if (status != napi_ok) {
1015            HILOG_ERROR("GetModuleFromName napi_get_named_property status != napi_ok");
1016        }
1017
1018        status = napi_unwrap(reinterpret_cast<napi_env>(this), exportInstance, reinterpret_cast<void**>(instance));
1019        if (status != napi_ok) {
1020            HILOG_ERROR("GetModuleFromName napi_unwrap status != napi_ok");
1021        }
1022        exports = exportObj;
1023    }
1024    return scope.Escape(exports);
1025}
1026
1027napi_value ArkNativeEngine::CreatePromise(NativeDeferred** deferred)
1028{
1029    panda::EscapeLocalScope scope(vm_);
1030    Local<PromiseCapabilityRef> capability = PromiseCapabilityRef::New(vm_);
1031    if (capability->IsUndefined()) {
1032        return JsValueFromLocalValue(scope.Escape(JSValueRef::Undefined(vm_)));
1033    }
1034    *deferred = new ArkNativeDeferred(this, capability);
1035    Local<JSValueRef> promiseValue = capability->GetPromise(vm_);
1036    return JsValueFromLocalValue(scope.Escape(promiseValue));
1037}
1038
1039panda::Local<panda::ObjectRef> ArkNativeEngine::LoadModuleByName(const std::string& moduleName, bool isAppModule,
1040    const std::string& param, const std::string& instanceName, void* instance, const std::string& path)
1041{
1042    panda::EscapeLocalScope scope(vm_);
1043    Local<ObjectRef> exports(JSValueRef::Undefined(vm_));
1044    NativeModuleManager* moduleManager = NativeModuleManager::GetInstance();
1045    std::string errInfo = "";
1046    NativeModule* module = moduleManager->LoadNativeModule(moduleName.c_str(),
1047        path.empty() ? nullptr : path.c_str(), isAppModule, errInfo);
1048    if (module != nullptr) {
1049        Local<ObjectRef> exportObj = ObjectRef::New(vm_);
1050        NapiPropertyDescriptor paramProperty, instanceProperty;
1051        Local<StringRef> paramStr = StringRef::NewFromUtf8(vm_, param.c_str(), param.size());
1052        napi_value paramValue = JsValueFromLocalValue(paramStr);
1053        paramProperty.utf8name = "param";
1054        paramProperty.value = paramValue;
1055        Local<ObjectRef> instanceValue = ObjectRef::New(vm_);
1056        Local<StringRef> key = StringRef::GetNapiWrapperString(vm_);
1057        if (instance == nullptr && instanceValue->Has(vm_, key)) {
1058            Local<ObjectRef> wrapper = instanceValue->Get(vm_, key);
1059            auto ref = reinterpret_cast<NativeReference*>(wrapper->GetNativePointerField(vm_, 0));
1060            wrapper->SetNativePointerField(vm_, 0, nullptr, nullptr, nullptr, 0);
1061            instanceValue->Delete(vm_, key);
1062            delete ref;
1063        } else {
1064            Local<ObjectRef> object = ObjectRef::New(vm_);
1065            NativeReference* ref = nullptr;
1066            Local<JSValueRef> value(instanceValue);
1067            ref = new ArkNativeReference(this, value, 0, true, nullptr, instance, nullptr);
1068
1069            object->SetNativePointerFieldCount(vm_, 1);
1070            object->SetNativePointerField(vm_, 0, ref, nullptr, nullptr, 0);
1071            PropertyAttribute attr(object, true, false, true);
1072            instanceValue->DefineProperty(vm_, key, attr);
1073        }
1074        instanceProperty.utf8name = instanceName.c_str();
1075        instanceProperty.value = JsValueFromLocalValue(instanceValue);
1076        SetModuleName(exportObj, module->name);
1077        NapiDefineProperty(reinterpret_cast<napi_env>(this), exportObj, paramProperty);
1078        NapiDefineProperty(reinterpret_cast<napi_env>(this), exportObj, instanceProperty);
1079
1080        MoudleNameLocker nameLocker(module->name);
1081        module->registerCallback(reinterpret_cast<napi_env>(this), JsValueFromLocalValue(exportObj));
1082        exports = exportObj;
1083    }
1084    return scope.Escape(exports);
1085}
1086
1087void ArkNativeEngine::Loop(LoopMode mode, bool needSync)
1088{
1089    LocalScope scope(vm_);
1090    NativeEngine::Loop(mode, needSync);
1091    panda::JSNApi::ExecutePendingJob(vm_);
1092}
1093
1094void ArkNativeEngine::SetModuleName(Local<ObjectRef> &nativeObj, std::string moduleName)
1095{
1096#ifdef ENABLE_HITRACE
1097    if (ArkNativeEngine::napiProfilerEnabled) {
1098        Local<StringRef> moduleNameStr = StringRef::NewFromUtf8(vm_, moduleName.c_str(), moduleName.size());
1099        Local<StringRef> key = StringRef::NewFromUtf8(vm_, PANDA_MODULE_NAME);
1100        nativeObj->Set(vm_, key, moduleNameStr);
1101    }
1102#endif
1103}
1104
1105static void ConcurrentCallbackFunc(Local<JSValueRef> result, bool success, void *taskInfo, void *data)
1106{
1107    if (data == nullptr) {
1108        return;
1109    }
1110    auto engine = static_cast<ArkNativeEngine *>(data);
1111    auto concurrentCallbackFunc = engine->GetConcurrentCallbackFunc();
1112    if (concurrentCallbackFunc == nullptr) {
1113        return;
1114    }
1115    napi_env env = reinterpret_cast<napi_env>(engine);
1116    concurrentCallbackFunc(env, ArkNativeEngine::ArkValueToNapiValue(env, result), success, taskInfo);
1117}
1118
1119bool ArkNativeEngine::InitTaskPoolThread(NativeEngine* engine, NapiConcurrentCallback callback)
1120{
1121    concurrentCallbackFunc_ = callback;
1122    return JSNApi::InitForConcurrentThread(vm_, ConcurrentCallbackFunc, static_cast<void *>(this));
1123}
1124
1125bool ArkNativeEngine::InitTaskPoolThread(napi_env env, NapiConcurrentCallback callback)
1126{
1127    concurrentCallbackFunc_ = callback;
1128    return JSNApi::InitForConcurrentThread(vm_, ConcurrentCallbackFunc, static_cast<void *>(this));
1129}
1130
1131bool ArkNativeEngine::InitTaskPoolFunc(napi_env env, napi_value func, void* taskInfo)
1132{
1133    LocalScope scope(vm_);
1134    Local<JSValueRef> function = LocalValueFromJsValue(func);
1135    return JSNApi::InitForConcurrentFunction(vm_, function, taskInfo);
1136}
1137
1138bool ArkNativeEngine::HasPendingJob() const
1139{
1140    return JSNApi::HasPendingJob(vm_);
1141}
1142
1143bool ArkNativeEngine::IsProfiling() const
1144{
1145    return JSNApi::IsProfiling(vm_);
1146}
1147
1148bool ArkNativeEngine::IsExecutingPendingJob() const
1149{
1150    return panda::JSNApi::IsExecutingPendingJob(vm_);
1151}
1152
1153void* ArkNativeEngine::GetCurrentTaskInfo() const
1154{
1155    return JSNApi::GetCurrentTaskInfo(vm_);
1156}
1157
1158void ArkNativeEngine::ClearCurrentTaskInfo()
1159{
1160    JSNApi::ClearCurrentTaskInfo(vm_);
1161}
1162
1163void ArkNativeEngine::TerminateExecution() const
1164{
1165    DFXJSNApi::TerminateExecution(vm_);
1166}
1167
1168void ArkNativeEngine::NotifyTaskBegin() const
1169{
1170    JSNApi::NotifyTaskBegin(vm_);
1171}
1172
1173void ArkNativeEngine::NotifyTaskFinished() const
1174{
1175    JSNApi::NotifyTaskFinished(vm_);
1176}
1177
1178napi_value ArkNativeEngine::CallFunction(
1179    napi_value thisVar, napi_value function, napi_value const* argv, size_t argc)
1180{
1181    if (function == nullptr) {
1182        return nullptr;
1183    }
1184    panda::EscapeLocalScope scope(vm_);
1185    Local<JSValueRef> thisObj = JSValueRef::Undefined(vm_);
1186    if (thisVar != nullptr) {
1187        thisObj = LocalValueFromJsValue(thisVar);
1188    }
1189    Local<FunctionRef> funcObj = LocalValueFromJsValue(function);
1190    std::vector<Local<JSValueRef>> args;
1191    args.reserve(argc);
1192    for (size_t i = 0; i < argc; i++) {
1193        if (argv[i] != nullptr) {
1194            args.emplace_back(LocalValueFromJsValue(argv[i]));
1195        } else {
1196            args.emplace_back(JSValueRef::Undefined(vm_));
1197        }
1198    }
1199
1200    Local<JSValueRef> value = funcObj->Call(vm_, thisObj, args.data(), argc);
1201    if (panda::JSNApi::HasPendingException(vm_)) {
1202        HILOG_ERROR("pending exception when js function called");
1203        HILOG_ERROR("print exception info: ");
1204        panda::JSNApi::PrintExceptionInfo(vm_);
1205        return nullptr;
1206    }
1207
1208    return JsValueFromLocalValue(scope.Escape(value));
1209}
1210
1211bool ArkNativeEngine::NapiNewTypedArray(const EcmaVM* vm, NativeTypedArrayType typedArrayType,
1212                                        Local<panda::ArrayBufferRef> arrayBuf,
1213                                        size_t byte_offset, size_t length, napi_value* result)
1214{
1215    Local<panda::TypedArrayRef> typedArray;
1216    switch (typedArrayType) {
1217        case NATIVE_INT8_ARRAY:
1218            typedArray = panda::Int8ArrayRef::New(vm, arrayBuf, byte_offset, length);
1219            break;
1220        case NATIVE_UINT8_ARRAY:
1221            typedArray = panda::Uint8ArrayRef::New(vm, arrayBuf, byte_offset, length);
1222            break;
1223        case NATIVE_UINT8_CLAMPED_ARRAY:
1224            typedArray = panda::Uint8ClampedArrayRef::New(vm, arrayBuf, byte_offset, length);
1225            break;
1226        case NATIVE_INT16_ARRAY:
1227            typedArray = panda::Int16ArrayRef::New(vm, arrayBuf, byte_offset, length);
1228            break;
1229        case NATIVE_UINT16_ARRAY:
1230            typedArray = panda::Uint16ArrayRef::New(vm, arrayBuf, byte_offset, length);
1231            break;
1232        case NATIVE_INT32_ARRAY:
1233            typedArray = panda::Int32ArrayRef::New(vm, arrayBuf, byte_offset, length);
1234            break;
1235        case NATIVE_UINT32_ARRAY:
1236            typedArray = panda::Uint32ArrayRef::New(vm, arrayBuf, byte_offset, length);
1237            break;
1238        case NATIVE_FLOAT32_ARRAY:
1239            typedArray = panda::Float32ArrayRef::New(vm, arrayBuf, byte_offset, length);
1240            break;
1241        case NATIVE_FLOAT64_ARRAY:
1242            typedArray = panda::Float64ArrayRef::New(vm, arrayBuf, byte_offset, length);
1243            break;
1244        case NATIVE_BIGINT64_ARRAY:
1245            typedArray = panda::BigInt64ArrayRef::New(vm, arrayBuf, byte_offset, length);
1246            break;
1247        case NATIVE_BIGUINT64_ARRAY:
1248            typedArray = panda::BigUint64ArrayRef::New(vm, arrayBuf, byte_offset, length);
1249            break;
1250        default:
1251            *result = nullptr;
1252            return false;
1253    }
1254    *result = JsValueFromLocalValue(typedArray);
1255    return true;
1256}
1257
1258bool ArkNativeEngine::NapiNewSendableTypedArray(const EcmaVM* vm, NativeTypedArrayType typedArrayType,
1259                                                Local<panda::SendableArrayBufferRef> arrayBuf,
1260                                                size_t byte_offset, size_t length, napi_value* result)
1261{
1262    Local<panda::SendableTypedArrayRef> typedArray;
1263    switch (typedArrayType) {
1264        case NATIVE_INT8_ARRAY:
1265            typedArray = panda::SharedInt8ArrayRef::New(vm, arrayBuf, byte_offset, length);
1266            break;
1267        case NATIVE_UINT8_ARRAY:
1268            typedArray = panda::SharedUint8ArrayRef::New(vm, arrayBuf, byte_offset, length);
1269            break;
1270        case NATIVE_INT16_ARRAY:
1271            typedArray = panda::SharedInt16ArrayRef::New(vm, arrayBuf, byte_offset, length);
1272            break;
1273        case NATIVE_UINT16_ARRAY:
1274            typedArray = panda::SharedUint16ArrayRef::New(vm, arrayBuf, byte_offset, length);
1275            break;
1276        case NATIVE_INT32_ARRAY:
1277            typedArray = panda::SharedInt32ArrayRef::New(vm, arrayBuf, byte_offset, length);
1278            break;
1279        case NATIVE_UINT32_ARRAY:
1280            typedArray = panda::SharedUint32ArrayRef::New(vm, arrayBuf, byte_offset, length);
1281            break;
1282        case NATIVE_FLOAT32_ARRAY:
1283            typedArray = panda::SharedFloat32ArrayRef::New(vm, arrayBuf, byte_offset, length);
1284            break;
1285        case NATIVE_UINT8_CLAMPED_ARRAY:
1286            typedArray = panda::SharedUint8ClampedArrayRef::New(vm, arrayBuf, byte_offset, length);
1287            break;
1288        default:
1289            *result = nullptr;
1290            return false;
1291    }
1292    *result = JsValueFromLocalValue(typedArray);
1293    return true;
1294}
1295
1296NativeTypedArrayType ArkNativeEngine::GetTypedArrayType(panda::Local<panda::TypedArrayRef> typedArray)
1297{
1298    NativeTypedArrayType thisType = NATIVE_INT8_ARRAY;
1299    if (typedArray->IsInt32Array(vm_)) {
1300        thisType = NATIVE_INT32_ARRAY;
1301    } else if (typedArray->IsInt8Array(vm_)) {
1302        thisType = NATIVE_INT8_ARRAY;
1303    } else if (typedArray->IsUint8Array(vm_)) {
1304        thisType = NATIVE_UINT8_ARRAY;
1305    } else if (typedArray->IsUint8ClampedArray(vm_)) {
1306        thisType = NATIVE_UINT8_CLAMPED_ARRAY;
1307    } else if (typedArray->IsInt16Array(vm_)) {
1308        thisType = NATIVE_INT16_ARRAY;
1309    } else if (typedArray->IsUint16Array(vm_)) {
1310        thisType = NATIVE_UINT16_ARRAY;
1311    } else if (typedArray->IsUint32Array(vm_)) {
1312        thisType = NATIVE_UINT32_ARRAY;
1313    } else if (typedArray->IsFloat32Array(vm_)) {
1314        thisType = NATIVE_FLOAT32_ARRAY;
1315    } else if (typedArray->IsFloat64Array(vm_)) {
1316        thisType = NATIVE_FLOAT64_ARRAY;
1317    } else if (typedArray->IsBigInt64Array(vm_)) {
1318        thisType = NATIVE_BIGINT64_ARRAY;
1319    } else if (typedArray->IsBigUint64Array(vm_)) {
1320        thisType = NATIVE_BIGUINT64_ARRAY;
1321    }
1322
1323    return thisType;
1324}
1325
1326NativeTypedArrayType ArkNativeEngine::GetSendableTypedArrayType(panda::Local<panda::SendableTypedArrayRef> typedArray)
1327{
1328    NativeTypedArrayType thisType = NATIVE_INT8_ARRAY;
1329    if (typedArray->IsJSSharedInt8Array(vm_)) {
1330        thisType = NATIVE_INT8_ARRAY;
1331    } else if (typedArray->IsJSSharedUint8Array(vm_)) {
1332        thisType = NATIVE_UINT8_ARRAY;
1333    } else if (typedArray->IsJSSharedInt16Array(vm_)) {
1334        thisType = NATIVE_INT16_ARRAY;
1335    } else if (typedArray->IsJSSharedUint16Array(vm_)) {
1336        thisType = NATIVE_UINT16_ARRAY;
1337    } else if (typedArray->IsJSSharedInt32Array(vm_)) {
1338        thisType = NATIVE_INT32_ARRAY;
1339    } else if (typedArray->IsJSSharedUint32Array(vm_)) {
1340        thisType = NATIVE_UINT32_ARRAY;
1341    } else if (typedArray->IsJSSharedFloat32Array(vm_)) {
1342        thisType = NATIVE_FLOAT32_ARRAY;
1343    } else if (typedArray->IsJSSharedUint8ClampedArray(vm_)) {
1344        thisType = NATIVE_UINT8_CLAMPED_ARRAY;
1345    }
1346
1347    return thisType;
1348}
1349
1350/*
1351 * Before: input: 1. @ohos.hilog
1352                  2. @system.app (NATIVE_MODULE contains this name)
1353 * After: return: 1.@ohos:hilog
1354 *                2.@native:system.app
1355 */
1356std::string ArkNativeEngine::GetOhmurl(std::string path)
1357{
1358    const std::regex reg("@(ohos|system)\\.(\\S+)");
1359    path.erase(0, path.find_first_not_of(" "));
1360    path.erase(path.find_last_not_of(" ") + 1);
1361    bool ret = std::regex_match(path, reg);
1362    if (!ret) {
1363        HILOG_ERROR("ArkNativeEngine:The module name doesn't comply with the naming rules");
1364        return "";
1365    }
1366    std::string systemModule = path.substr(1);
1367    if (NATIVE_MODULE.count(systemModule)) {
1368        return NATIVE_MODULE_PREFIX + systemModule;
1369    } else {
1370        int pos = static_cast<int>(path.find('.'));
1371        std::string systemKey = path.substr(pos + 1, systemModule.size());
1372        return OHOS_MODULE_PREFIX + systemKey;
1373    }
1374}
1375
1376Local<JSValueRef> ArkNativeEngine::NapiLoadNativeModule(std::string path)
1377{
1378    std::string key = GetOhmurl(path);
1379    if (key.size() == 0) {
1380        return JSValueRef::Undefined(vm_);
1381    }
1382    return panda::JSNApi::ExecuteNativeModule(vm_, key);
1383}
1384
1385ModuleTypes ArkNativeEngine::CheckLoadType(const std::string &path)
1386{
1387    if (path[0] == '@') {
1388        return ModuleTypes::NATIVE_MODULE;
1389    } else if (path.find("ets/") == 0) { // ets/xxx/xxx
1390        return ModuleTypes::MODULE_INNER_FILE;
1391    }
1392    return ModuleTypes::UNKNOWN;
1393}
1394
1395napi_value ArkNativeEngine::NapiLoadModule(const char* path, const char* module_info)
1396{
1397    if (path == nullptr) {
1398        HILOG_ERROR("ArkNativeEngine:The module name is empty");
1399        return nullptr;
1400    }
1401    panda::EscapeLocalScope scope(vm_);
1402    Local<JSValueRef> undefObj = JSValueRef::Undefined(vm_);
1403    Local<ObjectRef> exportObj(undefObj);
1404    std::string inputPath(path);
1405    std::string modulePath;
1406    if (module_info != nullptr) {
1407        modulePath = module_info;
1408    }
1409    switch (CheckLoadType(inputPath)) {
1410        case ModuleTypes::NATIVE_MODULE: {
1411            exportObj = NapiLoadNativeModule(inputPath);
1412            break;
1413        }
1414        case ModuleTypes::MODULE_INNER_FILE: {
1415            exportObj = panda::JSNApi::GetModuleNameSpaceFromFile(vm_, inputPath, modulePath);
1416            break;
1417        }
1418        default: {
1419            std::string msg = "ArkNativeEngine:NapiLoadModule input path:" + inputPath + " is invalid.";
1420            ThrowException(msg.c_str());
1421        }
1422    }
1423    if (!exportObj->IsObject(vm_)) {
1424        ThrowException("ArkNativeEngine:NapiLoadModule failed.");
1425        return JsValueFromLocalValue(scope.Escape(undefObj));
1426    }
1427    return JsValueFromLocalValue(scope.Escape(exportObj));
1428}
1429
1430napi_value ArkNativeEngine::NapiLoadModuleWithInfo(const char* path, const char* module_info)
1431{
1432    if (path == nullptr) {
1433        HILOG_ERROR("ArkNativeEngine:The module name is empty");
1434        return nullptr;
1435    }
1436    panda::EscapeLocalScope scope(vm_);
1437    Local<JSValueRef> undefObj = JSValueRef::Undefined(vm_);
1438    Local<ObjectRef> exportObj(undefObj);
1439    std::string inputPath(path);
1440    std::string modulePath;
1441    if (module_info != nullptr) {
1442        modulePath = module_info;
1443        exportObj = panda::JSNApi::GetModuleNameSpaceWithModuleInfo(vm_, inputPath, modulePath);
1444    } else {
1445        exportObj = NapiLoadNativeModule(inputPath);
1446    }
1447
1448    if (!exportObj->IsObject(vm_)) {
1449        ThrowException("ArkNativeEngine:NapiLoadModuleWithInfo failed.");
1450        return JsValueFromLocalValue(scope.Escape(undefObj));
1451    }
1452    return JsValueFromLocalValue(scope.Escape(exportObj));
1453}
1454
1455bool ArkNativeEngine::SuspendVMById(uint32_t tid)
1456{
1457#if !defined(PREVIEW) && !defined(IOS_PLATFORM)
1458    return DFXJSNApi::SuspendVMById(vm_, tid);
1459#else
1460    HILOG_WARN("ARK does not support dfx on windows");
1461    return false;
1462#endif
1463}
1464
1465void ArkNativeEngine::ResumeVMById(uint32_t tid)
1466{
1467#if !defined(PREVIEW) && !defined(IOS_PLATFORM)
1468    DFXJSNApi::ResumeVMById(vm_, tid);
1469#else
1470    HILOG_WARN("ARK does not support dfx on windows");
1471    return;
1472#endif
1473}
1474
1475void ArkNativeEngine::SetPackagePath(const std::string appLibPathKey, const std::vector<std::string>& packagePath)
1476{
1477    auto moduleManager = NativeModuleManager::GetInstance();
1478    if (moduleManager && !packagePath.empty()) {
1479        moduleManager->SetAppLibPath(appLibPathKey, packagePath);
1480    }
1481}
1482
1483napi_value ArkNativeEngine::CreateInstance(napi_value constructor, napi_value const *argv, size_t argc)
1484{
1485    if (constructor == nullptr) {
1486        return nullptr;
1487    }
1488    panda::EscapeLocalScope scope(vm_);
1489    Local<FunctionRef> value = LocalValueFromJsValue(constructor);
1490    std::vector<Local<JSValueRef>> args;
1491    args.reserve(argc);
1492    for (size_t i = 0; i < argc; i++) {
1493        if (argv[i] != nullptr) {
1494            args.emplace_back(LocalValueFromJsValue(argv[i]));
1495        } else {
1496            args.emplace_back(JSValueRef::Undefined(vm_));
1497        }
1498    }
1499    Local<JSValueRef> instance = value->Constructor(vm_, args.data(), argc);
1500    Local<ObjectRef> excep = panda::JSNApi::GetUncaughtException(vm_);
1501    if (!excep.IsNull()) {
1502        HILOG_ERROR("ArkNativeEngineImpl::CreateInstance occur Exception");
1503        return nullptr;
1504    }
1505    return JsValueFromLocalValue(scope.Escape(instance));
1506}
1507
1508NativeReference* ArkNativeEngine::CreateReference(napi_value value, uint32_t initialRefcount,
1509    bool flag, NapiNativeFinalize callback, void* data, void* hint, size_t nativeBindingSize)
1510{
1511    return new ArkNativeReference(this, value, initialRefcount, flag, callback, data, hint, false, nativeBindingSize);
1512}
1513
1514NativeReference* ArkNativeEngine::CreateAsyncReference(napi_value value, uint32_t initialRefcount,
1515    bool flag, NapiNativeFinalize callback, void* data, void* hint)
1516{
1517    return new ArkNativeReference(this, value, initialRefcount, flag, callback, data, hint, true);
1518}
1519
1520__attribute__((optnone)) void ArkNativeEngine::RunCallbacks(TriggerGCData *triggerGCData)
1521{
1522#ifdef ENABLE_HITRACE
1523    StartTrace(HITRACE_TAG_ACE, "RunTriggerGCTaskCallback");
1524#endif
1525    std::pair<void *, uint8_t> &param = *triggerGCData;
1526    JSNApi::TriggerIdleGC(reinterpret_cast<panda::ecmascript::EcmaVM *>(param.first),
1527        static_cast<panda::JSNApi::TRIGGER_IDLE_GC_TYPE>(param.second));
1528#ifdef ENABLE_HITRACE
1529    FinishTrace(HITRACE_TAG_ACE);
1530#endif
1531}
1532
1533__attribute__((optnone)) void ArkNativeEngine::RunCallbacks(ArkFinalizersPack *finalizersPack)
1534{
1535#ifdef ENABLE_HITRACE
1536    StartTrace(HITRACE_TAG_ACE, "RunFinalizeCallbacks:" + std::to_string(finalizersPack->GetNumFinalizers()));
1537#endif
1538    finalizersPack->ProcessAll();
1539#ifdef ENABLE_HITRACE
1540    FinishTrace(HITRACE_TAG_ACE);
1541#endif
1542}
1543
1544__attribute__((optnone)) void ArkNativeEngine::RunAsyncCallbacks(std::vector<RefFinalizer> *finalizers)
1545{
1546#ifdef ENABLE_HITRACE
1547    StartTrace(HITRACE_TAG_ACE, "RunFinalizeCallbacks:" + std::to_string(finalizers->size()));
1548#endif
1549    for (auto iter : (*finalizers)) {
1550        NapiNativeFinalize callback = iter.first;
1551        std::tuple<NativeEngine*, void*, void*> &param = iter.second;
1552        callback(reinterpret_cast<napi_env>(std::get<0>(param)),
1553                 std::get<1>(param), std::get<2>(param)); // 2 is the param.
1554    }
1555#ifdef ENABLE_HITRACE
1556    FinishTrace(HITRACE_TAG_ACE);
1557#endif
1558}
1559
1560void ArkNativeEngine::PostFinalizeTasks()
1561{
1562    if (IsInDestructor()) {
1563        return;
1564    }
1565    if (!pendingAsyncFinalizers_.empty()) {
1566        uv_work_t *asynWork = new uv_work_t;
1567        std::vector<RefFinalizer> *asyncFinalizers = new std::vector<RefFinalizer>();
1568        asyncFinalizers->swap(pendingAsyncFinalizers_);
1569        asynWork->data = reinterpret_cast<void *>(asyncFinalizers);
1570
1571        int ret = uv_queue_work_with_qos(GetUVLoop(), asynWork, [](uv_work_t *asynWork) {
1572            std::vector<RefFinalizer> *finalizers = reinterpret_cast<std::vector<RefFinalizer> *>(asynWork->data);
1573            RunAsyncCallbacks(finalizers);
1574            HILOG_DEBUG("uv_queue_work async running ");
1575            delete finalizers;
1576        }, [](uv_work_t *asynWork, int32_t) {
1577            delete asynWork;
1578        }, uv_qos_t(napi_qos_background));
1579        if (ret != 0) {
1580            HILOG_ERROR("uv_queue_work fail ret '%{public}d'", ret);
1581            RunAsyncCallbacks(asyncFinalizers);
1582            delete asynWork;
1583            delete asyncFinalizers;
1584        }
1585    }
1586    if (arkFinalizersPack_.Empty()) {
1587        return;
1588    }
1589    ArkFinalizersPack *finalizersPack = new ArkFinalizersPack();
1590    std::swap(arkFinalizersPack_, *finalizersPack);
1591    if (!IsMainThread()) {
1592        panda::JsiNativeScope nativeScope(vm_);
1593        RunCallbacks(finalizersPack);
1594        delete finalizersPack;
1595        return;
1596    }
1597    size_t bindingSize = finalizersPack->GetTotalNativeBindingSize();
1598    if (pendingFinalizersPackNativeBindingSize_ > FINALIZERS_PACK_PENDING_NATIVE_BINDING_SIZE_THRESHOLD &&
1599        bindingSize > 0) {
1600        HILOG_DEBUG("Pending Finalizers NativeBindingSize '%{public}zu' large than '%{public}zu', process sync.",
1601            pendingFinalizersPackNativeBindingSize_, FINALIZERS_PACK_PENDING_NATIVE_BINDING_SIZE_THRESHOLD);
1602        panda::JsiNativeScope nativeScope(vm_);
1603        RunCallbacks(finalizersPack);
1604        delete finalizersPack;
1605        return;
1606    }
1607    uv_work_t *syncWork = new uv_work_t;
1608    finalizersPack->RegisterFinishNotify([this] (size_t totalNativeBindingSize) {
1609        this->DecreasePendingFinalizersPackNativeBindingSize(totalNativeBindingSize);
1610    });
1611    IncreasePendingFinalizersPackNativeBindingSize(bindingSize);
1612
1613    syncWork->data = reinterpret_cast<void *>(finalizersPack);
1614    int ret = uv_queue_work_with_qos(GetUVLoop(), syncWork, [](uv_work_t *) {}, [](uv_work_t *syncWork, int32_t) {
1615        ArkFinalizersPack *finalizersPack = reinterpret_cast<ArkFinalizersPack*>(syncWork->data);
1616        RunCallbacks(finalizersPack);
1617        HILOG_DEBUG("uv_queue_work running");
1618        delete syncWork;
1619        delete finalizersPack;
1620    }, uv_qos_t(napi_qos_background));
1621    if (ret != 0) {
1622        HILOG_ERROR("uv_queue_work fail ret '%{public}d'", ret);
1623        panda::JsiNativeScope nativeScope(vm_);
1624        RunCallbacks(finalizersPack);
1625        delete syncWork;
1626        delete finalizersPack;
1627    }
1628}
1629
1630__attribute__((optnone)) void ArkNativeEngine::RunCallbacks(AsyncNativeCallbacksPack *callbacksPack)
1631{
1632#ifdef ENABLE_HITRACE
1633    StartTrace(HITRACE_TAG_ACE, "RunNativeCallbacks:" + std::to_string(callbacksPack->GetNumCallBacks()));
1634#endif
1635    callbacksPack->ProcessAll();
1636#ifdef ENABLE_HITRACE
1637    FinishTrace(HITRACE_TAG_ACE);
1638#endif
1639}
1640
1641void ArkNativeEngine::PostAsyncTask(AsyncNativeCallbacksPack *callBacksPack)
1642{
1643    if (IsInDestructor()) {
1644        delete callBacksPack;
1645        return;
1646    }
1647    uv_work_t *syncWork = new uv_work_t;
1648    syncWork->data = reinterpret_cast<void *>(callBacksPack);
1649
1650    int ret = uv_queue_work_with_qos(GetUVLoop(), syncWork, [](uv_work_t *) {}, [](uv_work_t *syncWork, int32_t) {
1651        AsyncNativeCallbacksPack *finalizers = reinterpret_cast<AsyncNativeCallbacksPack*>(syncWork->data);
1652        RunCallbacks(finalizers);
1653        HILOG_DEBUG("uv_queue_work running");
1654        delete syncWork;
1655        delete finalizers;
1656    }, uv_qos_t(napi_qos_background));
1657    if (ret != 0) {
1658        HILOG_ERROR("uv_queue_work fail ret '%{public}d'", ret);
1659        panda::JsiNativeScope nativeScope(vm_);
1660        RunCallbacks(callBacksPack);
1661        delete callBacksPack;
1662        delete syncWork;
1663    }
1664}
1665
1666void ArkNativeEngine::PostTriggerGCTask(TriggerGCData& data)
1667{
1668    TriggerGCData *triggerGCData = new TriggerGCData(data);
1669    uv_work_t *syncWork = new uv_work_t;
1670    syncWork->data = reinterpret_cast<void *>(triggerGCData);
1671    int ret = uv_queue_work_with_qos(GetUVLoop(), syncWork, [](uv_work_t *) {}, [](uv_work_t *syncWork, int32_t) {
1672            auto triggerGCData = reinterpret_cast<TriggerGCData *>(syncWork->data);
1673            RunCallbacks(triggerGCData);
1674            delete syncWork;
1675            delete triggerGCData;
1676        }, uv_qos_t(napi_qos_user_initiated));
1677    if (ret != 0) {
1678        HILOG_ERROR("uv_queue_work fail ret '%{public}d'", ret);
1679        RunCallbacks(triggerGCData);
1680        delete syncWork;
1681        delete triggerGCData;
1682    }
1683}
1684
1685#if defined(OHOS_PLATFORM) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
1686void ArkNativeEngine::SetAttribute(bool isLimitedWorker, panda::RuntimeOption &option)
1687{
1688    int arkProperties = OHOS::system::GetIntParameter<int>("persist.ark.properties", -1);
1689    std::string bundleName = OHOS::system::GetParameter("persist.ark.arkbundlename", "");
1690    std::string memConfigProperty = OHOS::system::GetParameter("persist.ark.mem_config_property", "");
1691    size_t gcThreadNum = OHOS::system::GetUintParameter<size_t>("persist.ark.gcthreads", 7);
1692    size_t longPauseTime = OHOS::system::GetUintParameter<size_t>("persist.ark.longpausetime", 40);
1693    bool asmInterpreterEnabled = OHOS::system::GetBoolParameter("persist.ark.asminterpreter", true);
1694    std::string asmOpcodeDisableRange = OHOS::system::GetParameter("persist.ark.asmopcodedisablerange", "");
1695    bool builtinsLazyEnabled = OHOS::system::GetBoolParameter("persist.ark.enablebuiltinslazy", true);
1696    option.SetEnableBuiltinsLazy(builtinsLazyEnabled);
1697    option.SetArkProperties(arkProperties);
1698    option.SetArkBundleName(bundleName);
1699    option.SetMemConfigProperty(memConfigProperty);
1700    option.SetGcThreadNum(gcThreadNum);
1701    option.SetLongPauseTime(longPauseTime);
1702    option.SetEnableAsmInterpreter(asmInterpreterEnabled);
1703    option.SetAsmOpcodeDisableRange(asmOpcodeDisableRange);
1704    option.SetIsWorker();
1705    option.SetIsRestrictedWorker(isLimitedWorker);
1706    HILOG_DEBUG("ArkNativeEngineImpl::CreateRuntimeFunc ark properties = %{public}d, bundlename = %{public}s",
1707        arkProperties, bundleName.c_str());
1708}
1709#endif
1710
1711NativeEngine* ArkNativeEngine::CreateRuntimeFunc(NativeEngine* engine, void* jsEngine, bool isLimitedWorker)
1712{
1713    panda::RuntimeOption option;
1714#if defined(OHOS_PLATFORM) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
1715    SetAttribute(isLimitedWorker, option);
1716#endif
1717    option.SetGcType(panda::RuntimeOption::GC_TYPE::GEN_GC);
1718    const int64_t poolSize = 0x1000000;
1719    option.SetGcPoolSize(poolSize);
1720#if !defined(PREVIEW) && !defined(IOS_PLATFORM)
1721    option.SetLogLevel(panda::RuntimeOption::LOG_LEVEL::INFO);
1722#endif
1723    option.SetDebuggerLibraryPath("");
1724    EcmaVM* vm = panda::JSNApi::CreateJSVM(option);
1725    if (vm == nullptr) {
1726        return nullptr;
1727    }
1728    // worker adaptation mergeabc
1729    const panda::ecmascript::EcmaVM* hostVM = reinterpret_cast<ArkNativeEngine*>(engine)->GetEcmaVm();
1730    panda::JSNApi::SynchronizVMInfo(vm, hostVM);
1731    ArkNativeEngine* arkEngine = new ArkNativeEngine(vm, jsEngine, isLimitedWorker);
1732    // init callback
1733    arkEngine->RegisterWorkerFunction(engine);
1734    arkEngine->SetHostEngine(engine);
1735    // sync apiVersion
1736    arkEngine->SetApiVersion(engine->GetApiVersion());
1737
1738    auto cleanEnv = [vm]() {
1739        if (vm != nullptr) {
1740            HILOG_DEBUG("cleanEnv is called");
1741            panda::JSNApi::DestroyJSVM(vm);
1742        }
1743    };
1744    arkEngine->SetCleanEnv(cleanEnv);
1745    if (hostVM != nullptr) {
1746        panda::JSNApi::AddWorker(const_cast<EcmaVM*>(hostVM), vm);
1747    }
1748    return arkEngine;
1749}
1750
1751void* ArkNativeEngine::CreateRuntime(bool isLimitedWorker)
1752{
1753    return ArkNativeEngine::CreateRuntimeFunc(this, jsEngine_, isLimitedWorker);
1754}
1755
1756void ArkNativeEngine::SetJsDumpThresholds(size_t thresholds)
1757{
1758    DFXJSNApi::SetJsDumpThresholds(vm_, thresholds);
1759}
1760
1761void ArkNativeEngine::SetAppFreezeFilterCallback(AppFreezeFilterCallback callback)
1762{
1763    DFXJSNApi::SetAppFreezeFilterCallback(vm_, callback);
1764}
1765
1766void ArkNativeEngine::StartCpuProfiler(const std::string& fileName)
1767{
1768    JSNApi::SetNativePtrGetter(vm_, reinterpret_cast<void*>(ArkNativeEngine::GetNativePtrCallBack));
1769    DFXJSNApi::StartCpuProfilerForFile(vm_, fileName);
1770}
1771
1772void ArkNativeEngine::StopCpuProfiler()
1773{
1774    DFXJSNApi::StopCpuProfilerForFile(vm_);
1775    JSNApi::SetNativePtrGetter(vm_, nullptr);
1776}
1777
1778void ArkNativeEngine::ResumeVM()
1779{
1780    DFXJSNApi::ResumeVM(vm_);
1781}
1782
1783bool ArkNativeEngine::SuspendVM()
1784{
1785    return DFXJSNApi::SuspendVM(vm_);
1786}
1787
1788bool ArkNativeEngine::IsSuspended()
1789{
1790    return DFXJSNApi::IsSuspended(vm_);
1791}
1792
1793bool ArkNativeEngine::CheckSafepoint()
1794{
1795    return DFXJSNApi::CheckSafepoint(vm_);
1796}
1797
1798void ArkNativeEngine::GetCurrentModuleInfo(std::string& moduleName, std::string& fileName, bool needRecordName)
1799{
1800    LocalScope scope(vm_);
1801    std::pair<std::string, std::string> moduleInfo = panda::JSNApi::GetCurrentModuleInfo(vm_, needRecordName);
1802    moduleName = moduleInfo.first; // if needRecordName is true, then moduleName is recordName.
1803    fileName = moduleInfo.second;
1804}
1805
1806bool ArkNativeEngine::GetIsBundle()
1807{
1808    LocalScope scope(vm_);
1809    return panda::JSNApi::IsBundle(vm_);
1810}
1811
1812bool ArkNativeEngine::GetIsNormalizedOhmUrlPack()
1813{
1814    LocalScope scope(vm_);
1815    return panda::JSNApi::IsNormalizedOhmUrlPack(vm_);
1816}
1817
1818bool ArkNativeEngine::GetIsDebugModeEnabled()
1819{
1820    LocalScope scope(vm_);
1821    return panda::JSNApi::IsDebugModeEnabled(vm_);
1822}
1823
1824std::string ArkNativeEngine::GetBundleName()
1825{
1826    LocalScope scope(vm_);
1827    return panda::JSNApi::GetBundleName(vm_);
1828}
1829
1830std::string ArkNativeEngine::GetPkgName(const std::string &moduleName)
1831{
1832    LocalScope scope(vm_);
1833    return panda::JSNApi::GetPkgName(vm_, moduleName);
1834}
1835
1836int ArkNativeEngine::GetProcessStartRealTime()
1837{
1838    LocalScope scope(vm_);
1839    return panda::JSNApi::GetStartRealTime(vm_);
1840}
1841
1842bool ArkNativeEngine::IsExecuteModuleInAbcFile(std::string bundleName, std::string moduleName, std::string ohmurl)
1843{
1844    LocalScope scope(vm_);
1845    return panda::JSNApi::IsExecuteModuleInAbcFile(vm_, bundleName, moduleName, ohmurl);
1846}
1847
1848napi_value ArkNativeEngine::ValueToNapiValue(JSValueWrapper& value)
1849{
1850    Global<JSValueRef> arkValue = value;
1851    return JsValueFromLocalValue(arkValue.ToLocal(vm_));
1852}
1853
1854napi_value ArkNativeEngine::ArkValueToNapiValue(napi_env env, Local<JSValueRef> value)
1855{
1856    return JsValueFromLocalValue(value);
1857}
1858
1859std::string ArkNativeEngine::GetSourceCodeInfo(napi_value value, ErrorPos pos)
1860{
1861    if (value == nullptr || pos.first == 0) {
1862        return "";
1863    }
1864
1865    LocalScope scope(vm_);
1866    Local<panda::FunctionRef> func = LocalValueFromJsValue(value);
1867    uint32_t line = pos.first;
1868    uint32_t column = pos.second;
1869    Local<panda::StringRef> sourceCode = func->GetSourceCode(vm_, line);
1870    std::string sourceCodeStr = sourceCode->ToString(vm_);
1871    if (sourceCodeStr.empty()) {
1872        return "";
1873    }
1874    std::string sourceCodeInfo = "SourceCode:\n";
1875    sourceCodeInfo.append(sourceCodeStr).append("\n");
1876    for (uint32_t k = 1; k < column; k++) {
1877        sourceCodeInfo.push_back(' ');
1878    }
1879    sourceCodeInfo.append("^\n");
1880    return sourceCodeInfo;
1881}
1882
1883void ArkNativeEngine::TriggerFatalException(panda::Local<panda::JSValueRef> exceptionValue)
1884{
1885    panda::JSNApi::ThrowException(GetEcmaVm(), exceptionValue);
1886    HandleUncaughtException();
1887}
1888
1889bool ArkNativeEngine::AdjustExternalMemory(int64_t ChangeInBytes, int64_t* AdjustedValue)
1890{
1891    return true;
1892}
1893
1894void ArkNativeEngine::SetPromiseRejectCallback(NativeReference* rejectCallbackRef, NativeReference* checkCallbackRef)
1895{
1896    if (rejectCallbackRef == nullptr || checkCallbackRef == nullptr) {
1897        HILOG_ERROR("rejectCallbackRef or checkCallbackRef is nullptr");
1898        return;
1899    }
1900    promiseRejectCallbackRef_ = rejectCallbackRef;
1901    checkCallbackRef_ = checkCallbackRef;
1902    JSNApi::SetHostPromiseRejectionTracker(vm_, reinterpret_cast<void*>(PromiseRejectCallback),
1903                                           reinterpret_cast<void*>(this));
1904}
1905
1906void ArkNativeEngine::PromiseRejectCallback(void* info)
1907{
1908    panda::PromiseRejectInfo* promiseRejectInfo = reinterpret_cast<panda::PromiseRejectInfo*>(info);
1909    ArkNativeEngine* env = reinterpret_cast<ArkNativeEngine*>(promiseRejectInfo->GetData());
1910
1911    if (env == nullptr) {
1912        HILOG_ERROR("engine is nullptr");
1913        return;
1914    }
1915
1916    if (env->promiseRejectCallbackRef_ == nullptr || env->checkCallbackRef_ == nullptr) {
1917        HILOG_ERROR("promiseRejectCallbackRef or checkCallbackRef is nullptr");
1918        return;
1919    }
1920    panda::ecmascript::EcmaVM* vm = const_cast<EcmaVM*>(env->GetEcmaVm());
1921    LocalScope scope(vm);
1922    Local<JSValueRef> promise = promiseRejectInfo->GetPromise();
1923    Local<JSValueRef> reason = promiseRejectInfo->GetReason();
1924    panda::PromiseRejectInfo::PROMISE_REJECTION_EVENT operation = promiseRejectInfo->GetOperation();
1925
1926    Local<JSValueRef> type(IntegerRef::New(vm, static_cast<int32_t>(operation)));
1927
1928    Local<JSValueRef> args[] = {type, promise, reason};
1929
1930    napi_value promiseNapiRejectCallback = env->promiseRejectCallbackRef_->Get(env);
1931    Local<FunctionRef> promiseRejectCallback = LocalValueFromJsValue(promiseNapiRejectCallback);
1932    if (!promiseRejectCallback.IsEmpty()) {
1933        promiseRejectCallback->Call(vm, JSValueRef::Undefined(vm), args, 3); // 3 args size
1934    }
1935
1936    if (operation == panda::PromiseRejectInfo::PROMISE_REJECTION_EVENT::REJECT) {
1937        Local<JSValueRef> checkCallback = LocalValueFromJsValue(env->checkCallbackRef_->Get(env));
1938        if (!checkCallback.IsEmpty()) {
1939            JSNApi::SetHostEnqueueJob(vm, checkCallback, panda::QueueType::QUEUE_SCRIPT);
1940        }
1941    }
1942}
1943
1944void ArkNativeEngine::DumpHeapSnapshot(const std::string& path, bool isVmMode, DumpFormat dumpFormat,
1945                                       bool isPrivate, bool captureNumericValue)
1946{
1947    panda::ecmascript::DumpSnapShotOption dumpOption;
1948    dumpOption.isVmMode = isVmMode;
1949    dumpOption.isSync = true;
1950    if (dumpFormat == DumpFormat::JSON) {
1951        dumpOption.dumpFormat = panda::ecmascript::DumpFormat::JSON;
1952        dumpOption.isPrivate = isPrivate;
1953        dumpOption.captureNumericValue = captureNumericValue;
1954        DFXJSNApi::DumpHeapSnapshot(vm_, path, dumpOption);
1955    }
1956    if (dumpFormat == DumpFormat::BINARY) {
1957        dumpOption.dumpFormat = panda::ecmascript::DumpFormat::BINARY;
1958        DFXJSNApi::DumpHeapSnapshot(vm_, path, dumpOption);
1959    }
1960    if (dumpFormat == DumpFormat::OTHER) {
1961        dumpOption.dumpFormat = panda::ecmascript::DumpFormat::OTHER;
1962        DFXJSNApi::DumpHeapSnapshot(vm_, path, dumpOption); // 2:enum is 2
1963    }
1964}
1965
1966void ArkNativeEngine::DumpCpuProfile()
1967{
1968    DFXJSNApi::DumpCpuProfile(vm_);
1969}
1970
1971void ArkNativeEngine::DumpHeapSnapshot(bool isVmMode, DumpFormat dumpFormat, bool isPrivate, bool isFullGC)
1972{
1973    panda::ecmascript::DumpSnapShotOption dumpOption;
1974    dumpOption.isVmMode = isVmMode;
1975    dumpOption.isPrivate = isPrivate;
1976    dumpOption.isFullGC = isFullGC;
1977    dumpOption.isSync = false;
1978    if (dumpFormat == DumpFormat::JSON) {
1979        dumpOption.dumpFormat = panda::ecmascript::DumpFormat::JSON;
1980        DFXJSNApi::DumpHeapSnapshot(vm_, dumpOption);
1981    }
1982    if (dumpFormat == DumpFormat::BINARY) {
1983        dumpOption.dumpFormat = panda::ecmascript::DumpFormat::BINARY;
1984        DFXJSNApi::DumpHeapSnapshot(vm_, dumpOption);
1985    }
1986    if (dumpFormat == DumpFormat::OTHER) {
1987        dumpOption.dumpFormat = panda::ecmascript::DumpFormat::OTHER;
1988        DFXJSNApi::DumpHeapSnapshot(vm_, dumpOption);
1989    }
1990}
1991
1992bool ArkNativeEngine::BuildNativeAndJsStackTrace(std::string& stackTraceStr)
1993{
1994#if !defined(PREVIEW) && !defined(IOS_PLATFORM)
1995    return DFXJSNApi::BuildNativeAndJsStackTrace(vm_, stackTraceStr);
1996#else
1997    HILOG_WARN("ARK does not support dfx on windows");
1998    return false;
1999#endif
2000}
2001
2002bool ArkNativeEngine::BuildJsStackTrace(std::string& stackTraceStr)
2003{
2004#if !defined(PREVIEW) && !defined(IOS_PLATFORM)
2005    return DFXJSNApi::BuildJsStackTrace(vm_, stackTraceStr);
2006#else
2007    HILOG_WARN("ARK does not support dfx on windows");
2008    return false;
2009#endif
2010}
2011
2012bool ArkNativeEngine::BuildJsStackInfoListWithCustomDepth(std::vector<JsFrameInfo>& jsFrames)
2013{
2014#if !defined(PREVIEW) && !defined(IOS_PLATFORM)
2015    bool sign = DFXJSNApi::BuildJsStackInfoList(vm_, gettid(), jsFrames);
2016    return sign;
2017#else
2018    HILOG_WARN("ARK does not support dfx on windows");
2019    return false;
2020#endif
2021}
2022
2023bool ArkNativeEngine::DeleteWorker(NativeEngine* workerEngine)
2024{
2025    if (workerEngine != nullptr) {
2026#if !defined(PREVIEW)
2027        const panda::ecmascript::EcmaVM* workerVM = reinterpret_cast<ArkNativeEngine*>(workerEngine)->GetEcmaVm();
2028        if (workerVM != nullptr) {
2029            return panda::JSNApi::DeleteWorker(vm_, const_cast<EcmaVM*>(workerVM));
2030        }
2031#else
2032        HILOG_WARN("ARK does not support dfx on windows");
2033#endif
2034        return false;
2035        }
2036    return false;
2037}
2038
2039bool ArkNativeEngine::StartHeapTracking(double timeInterval, bool isVmMode)
2040{
2041    return DFXJSNApi::StartHeapTracking(vm_, timeInterval, isVmMode);
2042}
2043
2044bool ArkNativeEngine::StopHeapTracking(const std::string &filePath)
2045{
2046    return DFXJSNApi::StopHeapTracking(vm_, filePath);
2047}
2048
2049#if !defined(PREVIEW)
2050void ArkNativeEngine::PrintStatisticResult()
2051{
2052    DFXJSNApi::PrintStatisticResult(vm_);
2053}
2054
2055void ArkNativeEngine::StartRuntimeStat()
2056{
2057    DFXJSNApi::StartRuntimeStat(vm_);
2058}
2059
2060void ArkNativeEngine::StopRuntimeStat()
2061{
2062    DFXJSNApi::StopRuntimeStat(vm_);
2063}
2064
2065size_t ArkNativeEngine::GetArrayBufferSize()
2066{
2067    return DFXJSNApi::GetArrayBufferSize(vm_);
2068}
2069
2070size_t ArkNativeEngine::GetHeapTotalSize()
2071{
2072    return DFXJSNApi::GetHeapTotalSize(vm_);
2073}
2074
2075size_t ArkNativeEngine::GetHeapUsedSize()
2076{
2077    return DFXJSNApi::GetHeapUsedSize(vm_);
2078}
2079
2080size_t ArkNativeEngine::GetHeapObjectSize()
2081{
2082    return DFXJSNApi::GetHeapObjectSize(vm_);
2083}
2084
2085size_t ArkNativeEngine::GetHeapLimitSize()
2086{
2087    return DFXJSNApi::GetHeapLimitSize(vm_);
2088}
2089
2090size_t ArkNativeEngine::GetProcessHeapLimitSize()
2091{
2092    return DFXJSNApi::GetProcessHeapLimitSize();
2093}
2094
2095size_t ArkNativeEngine::GetGCCount()
2096{
2097    return DFXJSNApi::GetGCCount(vm_);
2098}
2099
2100size_t ArkNativeEngine::GetGCDuration()
2101{
2102    return DFXJSNApi::GetGCDuration(vm_);
2103}
2104
2105size_t ArkNativeEngine::GetAccumulatedAllocateSize()
2106{
2107    return DFXJSNApi::GetAccumulatedAllocateSize(vm_);
2108}
2109
2110size_t ArkNativeEngine::GetAccumulatedFreeSize()
2111{
2112    return DFXJSNApi::GetAccumulatedFreeSize(vm_);
2113}
2114
2115size_t ArkNativeEngine::GetFullGCLongTimeCount()
2116{
2117    return DFXJSNApi::GetFullGCLongTimeCount(vm_);
2118}
2119
2120void ArkNativeEngine::NotifyApplicationState(bool inBackground)
2121{
2122    DFXJSNApi::NotifyApplicationState(vm_, inBackground);
2123    arkIdleMonitor_->NotifyChangeBackgroundState(inBackground);
2124}
2125
2126void ArkNativeEngine::NotifyIdleStatusControl(std::function<void(bool)> callback)
2127{
2128    DFXJSNApi::NotifyIdleStatusControl(vm_, callback);
2129}
2130
2131void ArkNativeEngine::NotifyIdleTime(int idleMicroSec)
2132{
2133    DFXJSNApi::NotifyIdleTime(vm_, idleMicroSec);
2134}
2135
2136void ArkNativeEngine::NotifyMemoryPressure(bool inHighMemoryPressure)
2137{
2138    DFXJSNApi::NotifyMemoryPressure(vm_, inHighMemoryPressure);
2139}
2140
2141void ArkNativeEngine::NotifyForceExpandState(int32_t value)
2142{
2143    switch (ForceExpandState(value)) {
2144        case ForceExpandState::FINISH_COLD_START:
2145            DFXJSNApi::NotifyFinishColdStart(vm_, true);
2146            break;
2147        case ForceExpandState::START_HIGH_SENSITIVE:
2148            DFXJSNApi::NotifyHighSensitive(vm_, true);
2149            break;
2150        case ForceExpandState::FINISH_HIGH_SENSITIVE:
2151            DFXJSNApi::NotifyHighSensitive(vm_, false);
2152            break;
2153        default:
2154            HILOG_ERROR("Invalid Force Expand State: %{public}d.", value);
2155            break;
2156    }
2157}
2158#else
2159void ArkNativeEngine::PrintStatisticResult()
2160{
2161    HILOG_WARN("ARK does not support dfx on windows");
2162}
2163
2164void ArkNativeEngine::StartRuntimeStat()
2165{
2166    HILOG_WARN("ARK does not support dfx on windows");
2167}
2168
2169void ArkNativeEngine::StopRuntimeStat()
2170{
2171    HILOG_WARN("ARK does not support dfx on windows");
2172}
2173
2174size_t ArkNativeEngine::GetArrayBufferSize()
2175{
2176    HILOG_WARN("ARK does not support dfx on windows");
2177    return 0;
2178}
2179
2180size_t ArkNativeEngine::GetHeapTotalSize()
2181{
2182    HILOG_WARN("ARK does not support dfx on windows");
2183    return 0;
2184}
2185
2186size_t ArkNativeEngine::GetHeapUsedSize()
2187{
2188    HILOG_WARN("ARK does not support dfx on windows");
2189    return 0;
2190}
2191
2192size_t ArkNativeEngine::GetHeapObjectSize()
2193{
2194    HILOG_WARN("ARK does not support dfx on windows");
2195    return 0;
2196}
2197
2198size_t ArkNativeEngine::GetHeapLimitSize()
2199{
2200    HILOG_WARN("ARK does not support dfx on windows");
2201    return 0;
2202}
2203
2204size_t ArkNativeEngine::GetProcessHeapLimitSize()
2205{
2206    HILOG_WARN("ARK does not support dfx on windows");
2207    return 0;
2208}
2209
2210size_t ArkNativeEngine::GetGCCount()
2211{
2212    HILOG_WARN("ARK does not support dfx on windows");
2213    return 0;
2214}
2215
2216size_t ArkNativeEngine::GetGCDuration()
2217{
2218    HILOG_WARN("ARK does not support dfx on windows");
2219    return 0;
2220}
2221
2222size_t ArkNativeEngine::GetAccumulatedAllocateSize()
2223{
2224    HILOG_WARN("ARK does not support dfx on windows");
2225    return 0;
2226}
2227
2228size_t ArkNativeEngine::GetAccumulatedFreeSize()
2229{
2230    HILOG_WARN("ARK does not support dfx on windows");
2231    return 0;
2232}
2233
2234size_t ArkNativeEngine::GetFullGCLongTimeCount()
2235{
2236    HILOG_WARN("ARK does not support dfx on windows");
2237    return 0;
2238}
2239
2240void ArkNativeEngine::NotifyApplicationState([[maybe_unused]] bool inBackground)
2241{
2242    HILOG_WARN("ARK does not support dfx on windows");
2243}
2244
2245void ArkNativeEngine::NotifyIdleStatusControl([[maybe_unused]] std::function<void(bool)> callback)
2246{
2247    HILOG_WARN("ARK does not support dfx on windows");
2248}
2249
2250void ArkNativeEngine::NotifyIdleTime([[maybe_unused]] int idleMicroSec)
2251{
2252    HILOG_WARN("ARK does not support dfx on windows");
2253}
2254
2255void ArkNativeEngine::NotifyMemoryPressure([[maybe_unused]] bool inHighMemoryPressure)
2256{
2257    HILOG_WARN("ARK does not support dfx on windows");
2258}
2259
2260void ArkNativeEngine::NotifyForceExpandState([[maybe_unused]] int32_t value)
2261{
2262    HILOG_WARN("ARK does not support dfx on windows");
2263}
2264#endif
2265
2266void ArkNativeEngine::SetMockModuleList(const std::map<std::string, std::string> &list)
2267{
2268    JSNApi::SetMockModuleList(vm_, list);
2269}
2270
2271void ArkNativeEngine::RegisterNapiUncaughtExceptionHandler(NapiUncaughtExceptionCallback callback)
2272{
2273    JSNApi::EnableUserUncaughtErrorHandler(vm_);
2274    napiUncaughtExceptionCallback_ = callback;
2275}
2276
2277void ArkNativeEngine::HandleUncaughtException()
2278{
2279    if (napiUncaughtExceptionCallback_ == nullptr) {
2280        return;
2281    }
2282    LocalScope scope(vm_);
2283    lastException_.Empty();
2284    Local<ObjectRef> exception = JSNApi::GetAndClearUncaughtException(vm_);
2285    if (!exception.IsEmpty() && !exception->IsHole()) {
2286        if (napiUncaughtExceptionCallback_ != nullptr) {
2287            napiUncaughtExceptionCallback_(ArkValueToNapiValue(reinterpret_cast<napi_env>(this), exception));
2288        }
2289    }
2290}
2291
2292bool ArkNativeEngine::HasPendingException()
2293{
2294    return panda::JSNApi::HasPendingException(vm_);
2295}
2296
2297void ArkNativeEngine::RegisterPermissionCheck(PermissionCheckCallback callback)
2298{
2299    if (permissionCheckCallback_ == nullptr) {
2300        permissionCheckCallback_ = callback;
2301    }
2302}
2303
2304bool ArkNativeEngine::ExecutePermissionCheck()
2305{
2306    if (permissionCheckCallback_ != nullptr) {
2307        return permissionCheckCallback_();
2308    } else {
2309        HILOG_INFO("permissionCheckCallback_ is still nullptr when executing permission check!");
2310        return true;
2311    }
2312}
2313
2314void ArkNativeEngine::RegisterTranslateBySourceMap(SourceMapCallback callback)
2315{
2316    if (SourceMapCallback_ == nullptr) {
2317        SourceMapCallback_ = callback;
2318    }
2319    // regedit SourceMapCallback to ark_js_runtime
2320    panda::JSNApi::SetSourceMapCallback(vm_, callback);
2321}
2322
2323void ArkNativeEngine::RegisterSourceMapTranslateCallback(SourceMapTranslateCallback callback)
2324{
2325    panda::JSNApi::SetSourceMapTranslateCallback(vm_, callback);
2326}
2327
2328std::string ArkNativeEngine::ExecuteTranslateBySourceMap(const std::string& rawStack)
2329{
2330    if (SourceMapCallback_ != nullptr) {
2331        return SourceMapCallback_(rawStack);
2332    } else {
2333        HILOG_WARN("SourceMapCallback_ is nullptr.");
2334        return rawStack;
2335    }
2336}
2337
2338bool ArkNativeEngine::IsMixedDebugEnabled()
2339{
2340    return JSNApi::IsMixedDebugEnabled(vm_);
2341}
2342
2343void ArkNativeEngine::NotifyNativeCalling(const void *nativeAddress)
2344{
2345    JSNApi::NotifyNativeCalling(vm_, nativeAddress);
2346}
2347
2348void ArkNativeEngine::AllowCrossThreadExecution() const
2349{
2350    JSNApi::AllowCrossThreadExecution(vm_);
2351}
2352
2353#if !defined(is_arkui_x) && defined(OHOS_PLATFORM)
2354std::string DumpHybridStack(const EcmaVM* vm)
2355{
2356    constexpr size_t skipframes = 5;
2357    auto unwinder = std::make_shared<OHOS::HiviewDFX::Unwinder>();
2358    std::vector<OHOS::HiviewDFX::DfxFrame> frames;
2359    unwinder->EnableMethodIdLocal(true);
2360    if (unwinder->UnwindLocal(false, false, DEFAULT_MAX_FRAME_NUM, skipframes)) {
2361        frames = unwinder->GetFrames();
2362    } else {
2363        HILOG_ERROR("Failed to unwind local");
2364    }
2365
2366    for (auto &frame : frames) {
2367        if (frame.isJsFrame) {
2368            DFXJSNApi::TranslateJSStackInfo(vm, frame.mapName, frame.line, frame.column);
2369        }
2370    }
2371
2372    return OHOS::HiviewDFX::Unwinder::GetFramesStr(frames);
2373}
2374#endif
2375
2376void ArkNativeEngine::PostLooperTriggerIdleGCTask()
2377{
2378#if defined(ENABLE_EVENT_HANDLER)
2379    std::shared_ptr<OHOS::AppExecFwk::EventRunner> mainThreadRunner =
2380        OHOS::AppExecFwk::EventRunner::GetMainEventRunner();
2381    if (mainThreadRunner.get() == nullptr) {
2382        HILOG_FATAL("ArkNativeEngine:: the mainEventRunner is nullptr");
2383        return;
2384    }
2385    auto callback = [this](OHOS::AppExecFwk::EventRunnerStage stage,
2386        const OHOS::AppExecFwk::StageInfo* info) -> int {
2387        switch (stage) {
2388            case OHOS::AppExecFwk::EventRunnerStage::STAGE_BEFORE_WAITING:
2389                arkIdleMonitor_->NotifyLooperIdleStart(info->timestamp, info->sleepTime);
2390                break;
2391            case OHOS::AppExecFwk::EventRunnerStage::STAGE_AFTER_WAITING:
2392                arkIdleMonitor_->NotifyLooperIdleEnd(info->timestamp);
2393                break;
2394            default:
2395                HILOG_ERROR("this branch is unreachable");
2396        }
2397        return 0;
2398    };
2399    uint32_t stage = (static_cast<uint32_t>(OHOS::AppExecFwk::EventRunnerStage::STAGE_BEFORE_WAITING) |
2400        static_cast<uint32_t>(OHOS::AppExecFwk::EventRunnerStage::STAGE_AFTER_WAITING));
2401    mainThreadRunner->GetEventQueue()->AddObserver(OHOS::AppExecFwk::Observer::ARKTS_GC, stage, callback);
2402#endif
2403}
2404
2405int32_t ArkNativeEngine::GetObjectHash(napi_env env, napi_value src)
2406{
2407    auto engine = reinterpret_cast<NativeEngine*>(env);
2408    auto vm = engine->GetEcmaVm();
2409    auto nativeValue = LocalValueFromJsValue(src);
2410    return DFXJSNApi::GetObjectHash(vm, nativeValue);
2411}
2412// LCOV_EXCL_STOP
2413
2414bool ArkNativeEngine::RunScriptPath(const char* path, bool checkPath)
2415{
2416    if (checkPath && !IsValidPandaFile(path)) {
2417        HILOG_ERROR("file is not exist or format is invalid");
2418        return false;
2419    }
2420    // LCOV_EXCL_START
2421    panda::JSExecutionScope executionScope(vm_);
2422    LocalScope scope(vm_);
2423    [[maybe_unused]] bool ret = panda::JSNApi::Execute(vm_, path, PANDA_MAIN_FUNCTION);
2424    if (panda::JSNApi::HasPendingException(vm_)) {
2425        HandleUncaughtException();
2426        return false;
2427    }
2428    // LCOV_EXCL_STOP
2429    return true;
2430}
2431
2432bool ArkNativeEngine::IsValidPandaFile(const char* path)
2433{
2434    if (path == nullptr) {
2435        HILOG_ERROR("file path is nullptr");
2436        return false;
2437    }
2438
2439    char filePath[PATH_MAX + 1] = { 0 };
2440    if (!RealPath(path, filePath, PATH_MAX + 1)) {
2441        HILOG_ERROR("failed to format path");
2442        return false;
2443    }
2444    struct stat fileStat;
2445    int ret = stat(filePath, &fileStat);
2446    if (ret != 0) {
2447        HILOG_ERROR("script file \"%{public}s\" is not exist", filePath);
2448        return false;
2449    }
2450
2451    if (!(fileStat.st_mode & S_IFREG)) {
2452        HILOG_ERROR("script path \"%{public}s\" is a directory", filePath);
2453        return false;
2454    }
2455    std::ifstream abcStream(filePath, std::ios::in | std::ios::binary);
2456
2457    constexpr size_t fileHeaderLength = sizeof(uint64_t);
2458    uint8_t fileHeader[fileHeaderLength] = { 0 };
2459    if (abcStream.is_open()) {
2460        size_t fileSize = fileStat.st_size;
2461        if (fileSize < fileHeaderLength) {
2462            HILOG_ERROR("faild to read file header, invalid format \"%{public}s\"", filePath);
2463            abcStream.close();
2464            return false;
2465        }
2466        abcStream.read(reinterpret_cast<char*>(fileHeader), fileHeaderLength);
2467        abcStream.close();
2468        return IsValidScriptBuffer(fileHeader, fileHeaderLength);
2469    }
2470    return false;
2471}
2472
2473bool ArkNativeEngine::IsValidScriptBuffer(uint8_t* scriptBuffer, size_t bufferSize)
2474{
2475    if (scriptBuffer == nullptr) {
2476        HILOG_ERROR("buffer is nullptr");
2477        return false;
2478    }
2479    constexpr size_t headerLen = sizeof(uint64_t);
2480    if (bufferSize < headerLen) {
2481        HILOG_ERROR("invalid buffer");
2482        return false;
2483    }
2484    constexpr char pandaFileHeader[headerLen] = "PANDA";
2485    const uint64_t bytePandaHeader = *reinterpret_cast<const uint64_t*>(pandaFileHeader);
2486    char fileHeader[headerLen] = { 0 };
2487    // Ensure destMax paramter is set correctly to avoid buffer overflows
2488    if (memcpy_s(fileHeader, sizeof(fileHeader), scriptBuffer, sizeof(fileHeader)) != 0) {
2489        HILOG_ERROR("faild to read file header of buffer");
2490        return false;
2491    }
2492
2493    uint64_t byteFileHeader = *reinterpret_cast<uint64_t*>(fileHeader);
2494    if (byteFileHeader != bytePandaHeader) {
2495        HILOG_ERROR("invalid format of file buffer");
2496        return false;
2497    }
2498    return true;
2499}
2500
2501// The security interface needs to be modified accordingly.
2502napi_value ArkNativeEngine::RunScriptBuffer(const char* path, std::vector<uint8_t>& buffer, bool isBundle)
2503{
2504    if (!IsValidScriptBuffer(buffer.data(), buffer.size())) {
2505        HILOG_ERROR("invalid script buffer");
2506        return nullptr;
2507    }
2508
2509    // LCOV_EXCL_START
2510    panda::EscapeLocalScope scope(vm_);
2511    [[maybe_unused]] bool ret = false;
2512    if (isBundle) {
2513        ret = panda::JSNApi::Execute(vm_, buffer.data(), buffer.size(), PANDA_MAIN_FUNCTION, path);
2514    } else {
2515        ret = panda::JSNApi::ExecuteModuleBuffer(vm_, buffer.data(), buffer.size(), path);
2516    }
2517
2518    if (panda::JSNApi::HasPendingException(vm_)) {
2519        HandleUncaughtException();
2520        return nullptr;
2521    }
2522    Local<JSValueRef> undefObj = JSValueRef::Undefined(vm_);
2523    // LCOV_EXCL_STOP
2524    return JsValueFromLocalValue(scope.Escape(undefObj));
2525}
2526
2527bool ArkNativeEngine::RunScriptBuffer(const std::string& path, uint8_t* buffer, size_t size, bool isBundle)
2528{
2529    if (!IsValidScriptBuffer(buffer, size)) {
2530        HILOG_ERROR("invalid script buffer");
2531        return false;
2532    }
2533
2534    // LCOV_EXCL_START
2535    panda::JSExecutionScope executionScope(vm_);
2536    LocalScope scope(vm_);
2537    bool ret = false;
2538    if (isBundle) {
2539        ret = panda::JSNApi::ExecuteSecure(vm_, buffer, size, PANDA_MAIN_FUNCTION, path);
2540    } else {
2541        ret = panda::JSNApi::ExecuteModuleBufferSecure(vm_, buffer, size, path);
2542    }
2543
2544    if (panda::JSNApi::HasPendingException(vm_)) {
2545        HandleUncaughtException();
2546        return false;
2547    }
2548    return ret;
2549    // LCOV_EXCL_STOP
2550}
2551
2552napi_value ArkNativeEngine::RunBufferScript(std::vector<uint8_t>& buffer)
2553{
2554    if (!IsValidScriptBuffer(buffer.data(), buffer.size())) {
2555        HILOG_ERROR("invalid script buffer");
2556        return nullptr;
2557    }
2558
2559    // LCOV_EXCL_START
2560    panda::EscapeLocalScope scope(vm_);
2561    [[maybe_unused]] bool ret = panda::JSNApi::Execute(vm_, buffer.data(), buffer.size(), PANDA_MAIN_FUNCTION);
2562
2563    if (panda::JSNApi::HasPendingException(vm_)) {
2564        HandleUncaughtException();
2565        return nullptr;
2566    }
2567    Local<JSValueRef> undefObj = JSValueRef::Undefined(vm_);
2568    return JsValueFromLocalValue(scope.Escape(undefObj));
2569    // LCOV_EXCL_STOP
2570}
2571
2572#define EXECUTE_BUFFER(functionName)                                                                 \
2573    if (panda::JSNApi::IsBundle(vm_)) {                                                              \
2574        /* FA doesn't enable securemem */                                                            \
2575        ret = panda::JSNApi::Execute(vm_, buffer, bufferSize, PANDA_MAIN_FUNCTION, desc);            \
2576    } else if (bufferSize != 0) {                                                                    \
2577        if (entryPoint == nullptr) {                                                                 \
2578            HILOG_DEBUG("Input entryPoint is nullptr, please input entryPoint for merged ESModule"); \
2579            /* this path for bundle and abc compiled by single module js */                          \
2580            ret = panda::JSNApi::functionName(vm_, buffer, bufferSize, PANDA_MAIN_FUNCTION, desc);   \
2581        } else {                                                                                     \
2582            /* this path for mergeabc with specific entryPoint */                                    \
2583            ret = panda::JSNApi::functionName(vm_, buffer, bufferSize, entryPoint, desc);            \
2584        }                                                                                            \
2585    } else {                                                                                         \
2586        /* this path for worker */                                                                   \
2587        ret = panda::JSNApi::Execute(vm_, desc, PANDA_MAIN_FUNCTION);                                \
2588    }
2589
2590napi_value ArkNativeEngine::RunActor(uint8_t* buffer, size_t bufferSize,
2591    const char* descriptor, char* entryPoint, bool checkPath)
2592{
2593    if (buffer == nullptr && descriptor == nullptr) {
2594        HILOG_ERROR("invalid param, both buffer and descriptor are nullptr");
2595        return nullptr;
2596    }
2597
2598    if ((buffer != nullptr && !IsValidScriptBuffer(buffer, bufferSize)) &&
2599        (checkPath && descriptor != nullptr && !IsValidPandaFile(descriptor))) {
2600        HILOG_ERROR("invalid param");
2601        return nullptr;
2602    }
2603
2604    // LCOV_EXCL_START
2605    panda::EscapeLocalScope scope(vm_);
2606    std::string desc(descriptor);
2607    [[maybe_unused]] bool ret = false;
2608    // if apiVersion > API11, use secure path.
2609    if (IsApplicationApiVersionAPI11Plus()) {
2610        EXECUTE_BUFFER(ExecuteSecure);
2611    } else {
2612        EXECUTE_BUFFER(Execute);
2613    }
2614    if (panda::JSNApi::HasPendingException(vm_)) {
2615        HandleUncaughtException();
2616        return nullptr;
2617    }
2618    Local<JSValueRef> undefObj = JSValueRef::Undefined(vm_);
2619    return JsValueFromLocalValue(scope.Escape(undefObj));
2620    // LCOV_EXCL_STOP
2621}
2622
2623panda::Local<panda::ObjectRef> ArkNativeEngine::LoadArkModule(const void* buffer,
2624    int32_t len, const std::string& fileName)
2625{
2626    panda::EscapeLocalScope scope(vm_);
2627    Local<ObjectRef> undefObj(JSValueRef::Undefined(vm_));
2628    if (buffer == nullptr || len <= 0 || fileName.empty()) {
2629        HILOG_ERROR("fileName is nullptr or source code is nullptr");
2630        return scope.Escape(undefObj);
2631    }
2632    if (!IsValidScriptBuffer(reinterpret_cast<uint8_t*>(const_cast<void*>(buffer)), len)) {
2633        HILOG_ERROR("invalid script buffer");
2634        return scope.Escape(undefObj);
2635    }
2636
2637    // LCOV_EXCL_START
2638    bool res = JSNApi::ExecuteModuleFromBuffer(vm_, buffer, len, fileName);
2639    if (!res) {
2640        HILOG_ERROR("Execute module failed");
2641        return scope.Escape(undefObj);
2642    }
2643
2644    Local<ObjectRef> exportObj = JSNApi::GetExportObjectFromBuffer(vm_, fileName, "default");
2645    if (exportObj->IsNull()) {
2646        HILOG_ERROR("Get export object failed");
2647        return scope.Escape(undefObj);
2648    }
2649
2650    HILOG_DEBUG("ArkNativeEngineImpl::LoadModule end");
2651    return scope.Escape(exportObj);
2652    // LCOV_EXCL_STOP
2653}
2654
2655bool ArkNativeEngine::ExecuteJsBin(const std::string& fileName, bool checkPath)
2656{
2657    if (checkPath && !IsValidPandaFile(fileName.c_str())) {
2658        HILOG_ERROR("faild to execute js bin, file is not exist or format is invalid");
2659        return false;
2660    }
2661    // LCOV_EXCL_START
2662    panda::JSExecutionScope executionScope(vm_);
2663    LocalScope scope(vm_);
2664    bool ret = JSNApi::Execute(vm_, fileName, PANDA_MAIN_FUNCTION);
2665    return ret;
2666    // LCOV_EXCL_STOP
2667}
2668