• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "ark_native_deferred.h"
23 #include "ark_native_reference.h"
24 #include "native_engine/native_property.h"
25 #include "native_engine/native_utils.h"
26 #include "securec.h"
27 #include "utils/log.h"
28 #if !defined(PREVIEW) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
29 #include "parameters.h"
30 #include <uv.h>
31 #endif
32 #ifdef ENABLE_HITRACE
33 #include "hitrace_meter.h"
34 #include "parameter.h"
35 #endif
36 
37 using panda::JsiRuntimeCallInfo;
38 using panda::BooleanRef;
39 using panda::ObjectRef;
40 using panda::StringRef;
41 using panda::Global;
42 using panda::FunctionRef;
43 using panda::PrimitiveRef;
44 using panda::ArrayBufferRef;
45 using panda::TypedArrayRef;
46 using panda::PromiseCapabilityRef;
47 using panda::NativePointerRef;
48 using panda::SymbolRef;
49 using panda::IntegerRef;
50 using panda::DateRef;
51 using panda::BigIntRef;
52 static constexpr auto PANDA_MAIN_FUNCTION = "_GLOBAL::func_main_0";
53 static constexpr auto PANDA_MODULE_NAME = "_GLOBAL_MODULE_NAME";
54 static constexpr auto PANDA_MODULE_NAME_LEN = 32;
55 static std::unordered_set<std::string> NATIVE_MODULE = {"system.app", "ohos.app", "system.router",
56     "system.curves", "ohos.curves", "system.matrix4", "ohos.matrix4"};
57 static constexpr auto NATIVE_MODULE_PREFIX = "@native:";
58 static constexpr auto OHOS_MODULE_PREFIX = "@ohos:";
59 #if !defined(PREVIEW) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
60 struct JsHeapDumpWork {
61     EcmaVM *vm;
62     uv_work_t work;
63     std::condition_variable *condition;
64     size_t limitSize;
65 };
66 static constexpr uint32_t DEC_TO_INT = 100;
67 static size_t g_threshold = OHOS::system::GetUintParameter<size_t>("persist.ark.leak.threshold", 85);
68 static constexpr int TIME_OUT = 20;
69 static size_t g_checkInterval = OHOS::system::GetUintParameter<size_t>("persist.ark.leak.checkinterval", 60);
70 static constexpr int DEFAULT_SLEEP_TIME = 100000; //poll every 0.1s
71 static bool g_enableProperty = OHOS::system::GetBoolParameter("persist.ark.leak.enableproperty", true);
72 static uint64_t g_lastHeapDumpTime = 0;
73 static bool g_debugLeak = OHOS::system::GetBoolParameter("debug.arkengine.tags.enableleak", false);
74 static constexpr uint64_t HEAP_DUMP_REPORT_INTERVAL = 24 * 3600 * 1000;
75 static constexpr uint64_t SEC_TO_MILSEC = 1000;
76 #endif
77 #ifdef ENABLE_HITRACE
78 constexpr auto NAPI_PROFILER_PARAM_SIZE = 10;
79 #endif
80 
81 std::string ArkNativeEngine::tempModuleName_ {""};
82 bool ArkNativeEngine::napiProfilerEnabled {false};
83 bool ArkNativeEngine::napiProfilerParamReaded {false};
84 PermissionCheckCallback ArkNativeEngine::permissionCheckCallback_ {nullptr};
85 
86 // To be delete
LocalValueToLocalNapiValue(panda::Local<panda::JSValueRef> local)87 napi_value LocalValueToLocalNapiValue(panda::Local<panda::JSValueRef> local)
88 {
89     return JsValueFromLocalValue(local);
90 }
91 
92 // To be delete
NapiValueToLocalValue(napi_value v)93 panda::Local<panda::JSValueRef> NapiValueToLocalValue(napi_value v)
94 {
95     return LocalValueFromJsValue(v);
96 }
97 
FunctionSetContainerId(const EcmaVM * vm,panda::Local<panda::JSValueRef> & value)98 void FunctionSetContainerId(const EcmaVM *vm, panda::Local<panda::JSValueRef> &value)
99 {
100     panda::Local<panda::FunctionRef> funcValue(value);
101     if (funcValue->IsNative(vm)) {
102         return;
103     }
104 
105     auto extraInfo = funcValue->GetData(vm);
106     if (extraInfo != nullptr) {
107         return;
108     }
109 
110     NapiFunctionInfo *funcInfo = NapiFunctionInfo::CreateNewInstance();
111     if (funcInfo == nullptr) {
112         HILOG_ERROR("funcInfo is nullptr");
113         return;
114     }
115     funcValue->SetData(vm, reinterpret_cast<void*>(funcInfo),
116         [](void *externalPointer, void *data) {
117             auto info = reinterpret_cast<NapiFunctionInfo*>(data);
118             if (info != nullptr) {
119                 delete info;
120                 info = nullptr;
121             }
122         }, true);
123 }
124 
125 #if !defined(PREVIEW) && !defined(IOS_PLATFORM) && !defined(IOS_PLATFORM)
IsFileNameFormat(char c)126 bool IsFileNameFormat(char c)
127 {
128     if (c >= '0' && c <= '9') {
129         return false;
130     }
131 
132     if (c >= 'a' && c <= 'z') {
133         return false;
134     }
135 
136     if (c >= 'A' && c <= 'Z') {
137         return false;
138     }
139 
140     if (c == '.' || c == '-' || c == '_') {
141         return false;
142     }
143 
144     return true;
145 }
146 
GetSelfProcName()147 std::string GetSelfProcName()
148 {
149     constexpr uint16_t READ_SIZE = 128;
150     std::ifstream fin;
151     fin.open("/proc/self/comm", std::ifstream::in);
152     if (!fin.is_open()) {
153         HILOG_ERROR("fin.is_open() false");
154         return "";
155     }
156     char readStr[READ_SIZE] = {'\0'};
157     fin.getline(readStr, READ_SIZE - 1);
158     fin.close();
159 
160     std::string ret = std::string(readStr);
161     ret.erase(std::remove_if(ret.begin(), ret.end(), IsFileNameFormat), ret.end());
162     return ret;
163 }
164 
IsInAppspawn()165 static bool IsInAppspawn()
166 {
167     const char *env = getenv("LD_PRELOAD");
168     if (env && strstr(env, "libclang_rt.asan.so") != nullptr) {
169         return true;
170     }
171     if (GetSelfProcName().find("appspawn") != std::string::npos && getppid() == 1) {
172         return true;
173     }
174     return false;
175 }
176 
177 #endif
178 
NapiDefineClass(napi_env env,const char * name,NapiNativeCallback callback,void * data,const NapiPropertyDescriptor * properties,size_t length)179 panda::Local<panda::JSValueRef> NapiDefineClass(napi_env env, const char* name, NapiNativeCallback callback,
180     void* data, const NapiPropertyDescriptor* properties, size_t length)
181 {
182     auto vm = const_cast<EcmaVM*>(reinterpret_cast<NativeEngine*>(env)->GetEcmaVm());
183     std::string className(name);
184     if (ArkNativeEngine::napiProfilerEnabled) {
185         className = ArkNativeEngine::tempModuleName_ + "." + name;
186     }
187 
188     NapiFunctionInfo* funcInfo = NapiFunctionInfo::CreateNewInstance();
189     if (funcInfo == nullptr) {
190         HILOG_ERROR("funcInfo is nullptr");
191         return panda::JSValueRef::Undefined(vm);
192     }
193     funcInfo->env = env;
194     funcInfo->callback = callback;
195     funcInfo->data = data;
196 
197     Local<panda::FunctionRef> fn = panda::FunctionRef::NewClassFunction(vm, ArkNativeFunctionCallBack,
198         [](void* externalPointer, void* data) {
199             auto info = reinterpret_cast<NapiFunctionInfo*>(data);
200                 if (info != nullptr) {
201                     delete info;
202                 }
203             },
204         reinterpret_cast<void*>(funcInfo), true);
205     Local<panda::ObjectRef> classPrototype = fn->GetFunctionPrototype(vm);
206     Local<panda::StringRef> fnName = panda::StringRef::NewFromUtf8(vm, className.c_str());
207     fn->SetName(vm, fnName);
208     Local<panda::ObjectRef> fnObj = fn->ToObject(vm);
209     for (size_t i = 0; i < length; i++) {
210         if (properties[i].attributes & NATIVE_STATIC) {
211             NapiDefineProperty(env, fnObj, properties[i]);
212         } else {
213             if (classPrototype->IsUndefined()) {
214                 HILOG_ERROR("ArkNativeEngineImpl::Class's prototype is null");
215                 continue;
216             }
217             reinterpret_cast<ArkNativeEngine*>(env)->SetModuleName(classPrototype, className);
218             NapiDefineProperty(env, classPrototype, properties[i]);
219         }
220     }
221 
222     return fn;
223 }
224 
225 struct MoudleNameLocker {
MoudleNameLockerMoudleNameLocker226     explicit MoudleNameLocker(std::string moduleName)
227     {
228         ArkNativeEngine::tempModuleName_ = moduleName;
229     }
~MoudleNameLockerMoudleNameLocker230     ~MoudleNameLocker()
231     {
232         ArkNativeEngine::tempModuleName_ = "";
233     }
234 };
235 
GetNativePtrCallBack(void * data)236 void* ArkNativeEngine::GetNativePtrCallBack(void* data)
237 {
238     if (data == nullptr) {
239         HILOG_ERROR("data is nullptr");
240         return nullptr;
241     }
242     auto info = reinterpret_cast<NapiFunctionInfo*>(data);
243     auto cb = reinterpret_cast<void*>(info->callback);
244     return cb;
245 }
246 
CheckArkApiAllowList(NativeModule * module,panda::ecmascript::ApiCheckContext context,panda::Local<panda::ObjectRef> & exportCopy)247 bool ArkNativeEngine::CheckArkApiAllowList(
248     NativeModule* module, panda::ecmascript::ApiCheckContext context, panda::Local<panda::ObjectRef>& exportCopy)
249 {
250     std::unique_ptr<ApiAllowListChecker>& apiAllowListChecker = module->apiAllowListChecker;
251     if (apiAllowListChecker != nullptr) {
252         const std::string apiPath = context.moduleName->ToString();
253         if ((*apiAllowListChecker)(apiPath)) {
254             CopyPropertyApiFilter(apiAllowListChecker, context.ecmaVm, context.exportObj, exportCopy, apiPath);
255         }
256         return true;
257     }
258     return false;
259 }
260 
CopyPropertyApiFilter(const std::unique_ptr<ApiAllowListChecker> & apiAllowListChecker,const EcmaVM * ecmaVm,const panda::Local<panda::ObjectRef> exportObj,panda::Local<panda::ObjectRef> & exportCopy,const std::string & apiPath)261 void ArkNativeEngine::CopyPropertyApiFilter(const std::unique_ptr<ApiAllowListChecker>& apiAllowListChecker,
262     const EcmaVM* ecmaVm, const panda::Local<panda::ObjectRef> exportObj, panda::Local<panda::ObjectRef>& exportCopy,
263     const std::string& apiPath)
264 {
265     panda::Local<panda::ArrayRef> namesArrayRef = exportObj->GetAllPropertyNames(ecmaVm, NATIVE_DEFAULT);
266     for (uint32_t i = 0; i < namesArrayRef->Length(ecmaVm); i++) {
267         const panda::Local<panda::JSValueRef> nameValue = panda::ArrayRef::GetValueAt(ecmaVm, namesArrayRef, i);
268         const panda::Local<panda::JSValueRef> value = exportObj->Get(ecmaVm, nameValue);
269         const std::string curPath = apiPath + "." + nameValue->ToString(ecmaVm)->ToString();
270         if ((*apiAllowListChecker)(curPath)) {
271             const std::string valueType = value->Typeof(ecmaVm)->ToString();
272             if (valueType == "object") {
273                 panda::Local<panda::ObjectRef> subObject = ObjectRef::New(ecmaVm);
274                 CopyPropertyApiFilter(apiAllowListChecker, ecmaVm, value, subObject, curPath);
275                 exportCopy->Set(ecmaVm, nameValue, subObject);
276                 HILOG_DEBUG("Set the package '%{public}s' to the allow list", curPath.c_str());
277             } else if (valueType == "function") {
278                 exportCopy->Set(ecmaVm, nameValue, value);
279                 HILOG_DEBUG("Set the function '%{public}s' to the allow list", curPath.c_str());
280             } else {
281                 exportCopy->Set(ecmaVm, nameValue, value);
282                 HILOG_DEBUG("Set the element type is '%{public}s::%{public}s' to the allow list", valueType.c_str(),
283                     curPath.c_str());
284             }
285         }
286     }
287 }
288 
289 
ArkNativeEngine(EcmaVM * vm,void * jsEngine,bool isLimitedWorker)290 ArkNativeEngine::ArkNativeEngine(EcmaVM* vm, void* jsEngine, bool isLimitedWorker) : NativeEngine(jsEngine),
291                                                                                      vm_(vm),
292                                                                                      topScope_(vm),
293                                                                                      isLimitedWorker_(isLimitedWorker)
294 {
295     HILOG_DEBUG("ArkNativeEngine::ArkNativeEngine");
296 #ifdef ENABLE_HITRACE
297     if (!ArkNativeEngine::napiProfilerParamReaded) {
298         char napiProfilerParam[NAPI_PROFILER_PARAM_SIZE] = {0};
299         int ret = GetParameter("persist.hiviewdfx.napiprofiler.enabled", "false",
300             napiProfilerParam, sizeof(napiProfilerParam));
301         if (ret > 0 && strcmp(napiProfilerParam, "true") == 0) {
302             ArkNativeEngine::napiProfilerEnabled = true;
303         }
304         ArkNativeEngine::napiProfilerParamReaded = true;
305     }
306 #endif
307     LocalScope scope(vm_);
308     Local<StringRef> requireInternalName = StringRef::NewFromUtf8(vm, "requireInternal");
309     void* requireData = static_cast<void*>(this);
310 
311     Local<FunctionRef> requireNapi =
312         FunctionRef::New(
313             vm,
314             [](JsiRuntimeCallInfo *info) -> Local<JSValueRef> {
315                 EcmaVM *ecmaVm = info->GetVM();
316                 panda::EscapeLocalScope scope(ecmaVm);
317                 NativeModuleManager* moduleManager = NativeModuleManager::GetInstance();
318                 ArkNativeEngine* arkNativeEngine = static_cast<ArkNativeEngine*>(info->GetData());
319                 Local<StringRef> moduleName(info->GetCallArgRef(0));
320                 NativeModule* module = nullptr;
321                 bool isAppModule = false;
322 #ifdef IOS_PLATFORM
323                 module = moduleManager->LoadNativeModule(moduleName->ToString().c_str(), nullptr, false, false,
324                                                          "", arkNativeEngine->isLimitedWorker_);
325 #else
326                 const uint32_t lengthMax = 2;
327                 if (info->GetArgsNumber() >= lengthMax) {
328                     Local<BooleanRef> ret(info->GetCallArgRef(1));
329                     isAppModule = ret->Value();
330                 }
331                 arkNativeEngine->isAppModule_ = isAppModule;
332                 if (info->GetArgsNumber() == 3) { // 3:Determine if the number of parameters is equal to 3
333                     Local<StringRef> path(info->GetCallArgRef(2)); // 2:Take the second parameter
334                     module =
335                         moduleManager->LoadNativeModule(moduleName->ToString().c_str(), path->ToString().c_str(),
336                             isAppModule, false, "", arkNativeEngine->isLimitedWorker_);
337                 } else if (info->GetArgsNumber() == 4) { // 4:Determine if the number of parameters is equal to 4
338                     Local<StringRef> path(info->GetCallArgRef(2)); // 2:Take the second parameter
339                     Local<StringRef> relativePath(info->GetCallArgRef(3)); // 3:Take the second parameter
340                     module =
341                         moduleManager->LoadNativeModule(moduleName->ToString().c_str(), nullptr, isAppModule, false,
342                             relativePath->ToString().c_str(), arkNativeEngine->isLimitedWorker_);
343                 } else {
344                     module =
345                         moduleManager->LoadNativeModule(moduleName->ToString().c_str(), nullptr, isAppModule, false,
346                                                         "", arkNativeEngine->isLimitedWorker_);
347                 }
348 #endif
349                 Local<JSValueRef> exports(JSValueRef::Undefined(ecmaVm));
350                 if (module != nullptr) {
351                     auto it = arkNativeEngine->loadedModules_.find(module);
352                     if (it != arkNativeEngine->loadedModules_.end()) {
353                         return scope.Escape(it->second.ToLocal(ecmaVm));
354                     }
355                     std::string strModuleName = moduleName->ToString();
356                     moduleManager->SetNativeEngine(strModuleName, arkNativeEngine);
357                     MoudleNameLocker nameLocker(strModuleName);
358 
359                     if (module->jsCode == nullptr && module->getABCCode != nullptr) {
360                         module->getABCCode(&module->jsCode, &module->jsCodeLen);
361                     }
362                     if (module->jsABCCode != nullptr || module->jsCode != nullptr) {
363                         char fileName[NAPI_PATH_MAX] = { 0 };
364                         const char* name = module->name;
365                         if (sprintf_s(fileName, sizeof(fileName), "lib%s.z.so/%s.js", name, name) == -1) {
366                             HILOG_ERROR("sprintf_s file name failed");
367                             return scope.Escape(exports);
368                         }
369                         HILOG_DEBUG("load js code from %{public}s", fileName);
370                         const void *buffer = nullptr;
371                         if (module->jsABCCode) {
372                             buffer = static_cast<const void *>(module->jsABCCode);
373                         } else {
374                             buffer = static_cast<const void *>(module->jsCode);
375                         }
376                         auto exportObject = arkNativeEngine->LoadArkModule(buffer, module->jsCodeLen, fileName);
377                         if (exportObject->IsUndefined()) {
378                             HILOG_ERROR("load module failed");
379                             return scope.Escape(exports);
380                         } else {
381                             exports = exportObject;
382                             arkNativeEngine->loadedModules_[module] = Global<JSValueRef>(ecmaVm, exports);
383                         }
384                     } else if (module->registerCallback != nullptr) {
385                         Local<ObjectRef> exportObj = ObjectRef::New(ecmaVm);
386 #ifdef ENABLE_HITRACE
387                         StartTrace(HITRACE_TAG_ACE, "NAPI module init, name = " + std::string(module->name));
388 #endif
389                         arkNativeEngine->SetModuleName(exportObj, module->name);
390                         module->registerCallback(reinterpret_cast<napi_env>(arkNativeEngine),
391                                                  JsValueFromLocalValue(exportObj));
392 #ifdef ENABLE_HITRACE
393                         FinishTrace(HITRACE_TAG_ACE);
394 #endif
395                         panda::Local<panda::ObjectRef> exportCopy = panda::ObjectRef::New(ecmaVm);
396                         panda::ecmascript::ApiCheckContext context{moduleManager, ecmaVm, moduleName, exportObj, scope};
397                         if (CheckArkApiAllowList(module, context, exportCopy)) {
398                             return scope.Escape(exportCopy);
399                         }
400                         exports = exportObj;
401                         arkNativeEngine->loadedModules_[module] = Global<JSValueRef>(ecmaVm, exports);
402                     } else {
403                         HILOG_ERROR("init module failed");
404                         return scope.Escape(exports);
405                     }
406                 }
407                 return scope.Escape(exports);
408             },
409             nullptr,
410             requireData);
411 
412     Local<FunctionRef> requireInternal =
413         FunctionRef::New(
414             vm,
415             [](JsiRuntimeCallInfo *info) -> Local<JSValueRef> {
416                 EcmaVM *ecmaVm = info->GetVM();
417                 panda::EscapeLocalScope scope(ecmaVm);
418                 NativeModuleManager* moduleManager = NativeModuleManager::GetInstance();
419                 ArkNativeEngine* arkNativeEngine = static_cast<ArkNativeEngine*>(info->GetData());
420                 Local<StringRef> moduleName(info->GetCallArgRef(0));
421                 NativeModule* module = moduleManager->LoadNativeModule(moduleName->ToString().c_str(), nullptr, false,
422                                                                        false, "", arkNativeEngine->isLimitedWorker_);
423                 Local<JSValueRef> exports(JSValueRef::Undefined(ecmaVm));
424                 MoudleNameLocker nameLocker(moduleName->ToString());
425                 if (module != nullptr && arkNativeEngine) {
426                     auto it = arkNativeEngine->loadedModules_.find(module);
427                     if (it != arkNativeEngine->loadedModules_.end()) {
428                         return scope.Escape(it->second.ToLocal(ecmaVm));
429                     }
430                     std::string strModuleName = moduleName->ToString();
431                     moduleManager->SetNativeEngine(strModuleName, arkNativeEngine);
432                     Local<ObjectRef> exportObj = ObjectRef::New(ecmaVm);
433                     if (exportObj->IsObject()) {
434                         arkNativeEngine->SetModuleName(exportObj, module->name);
435                         module->registerCallback(reinterpret_cast<napi_env>(arkNativeEngine),
436                                                  JsValueFromLocalValue(exportObj));
437                         exports = exportObj;
438                         arkNativeEngine->loadedModules_[module] = Global<JSValueRef>(ecmaVm, exports);
439                     } else {
440                         HILOG_ERROR("exportObject is nullptr");
441                         return scope.Escape(exports);
442                     }
443                 }
444                 return scope.Escape(exports);
445             },
446             nullptr,
447             requireData);
448 
449     Local<ObjectRef> global = panda::JSNApi::GetGlobalObject(vm);
450 #if !defined(PREVIEW)
451     Local<StringRef> requireName = StringRef::NewFromUtf8(vm, "requireNapi");
452     global->Set(vm, requireName, requireNapi);
453 #else
454     Local<StringRef> requireNapiPreview = StringRef::NewFromUtf8(vm, "requireNapiPreview");
455     global->Set(vm, requireNapiPreview, requireNapi);
456 #endif
457     global->Set(vm, requireInternalName, requireInternal);
458     JSNApi::SetNativePtrGetter(vm, reinterpret_cast<void*>(ArkNativeEngine::GetNativePtrCallBack));
459     // need to call init of base class.
460     NativeModuleManager* moduleManager = NativeModuleManager::GetInstance();
461     JSNApi::SetUnloadNativeModuleCallback(vm, std::bind(&NativeModuleManager::UnloadNativeModule,
462         moduleManager, std::placeholders::_1));
463     Init();
464     panda::JSNApi::SetLoop(vm, loop_);
465 }
466 
~ArkNativeEngine()467 ArkNativeEngine::~ArkNativeEngine()
468 {
469     HILOG_DEBUG("ArkNativeEngine::~ArkNativeEngine");
470     Deinit();
471     // Free cached objects
472     for (auto&& [module, exportObj] : loadedModules_) {
473         exportObj.FreeGlobalHandleAddr();
474     }
475     // Free callbackRef
476     if (promiseRejectCallbackRef_ != nullptr) {
477         delete promiseRejectCallbackRef_;
478     }
479     if (checkCallbackRef_ != nullptr) {
480         delete checkCallbackRef_;
481     }
482     StopMonitorJSHeapUsage();
483 }
484 
StartNapiProfilerTrace(panda::JsiRuntimeCallInfo * runtimeInfo)485 static inline void StartNapiProfilerTrace(panda::JsiRuntimeCallInfo *runtimeInfo)
486 {
487 #ifdef ENABLE_HITRACE
488         if (ArkNativeEngine::napiProfilerEnabled) {
489             EcmaVM *vm = runtimeInfo->GetVM();
490             LocalScope scope(vm);
491             Local<panda::FunctionRef> fn = runtimeInfo->GetFunctionRef();
492             Local<panda::StringRef> nameRef = fn->GetName(vm);
493             char threadName[128];
494             prctl(PR_GET_NAME, threadName);
495             StartTraceArgs(HITRACE_TAG_ACE, "Napi called:%s, tname:%s", nameRef->ToString().c_str(), threadName);
496         }
497 #endif
498 }
499 
FinishNapiProfilerTrace()500 static inline void FinishNapiProfilerTrace()
501 {
502 #ifdef ENABLE_HITRACE
503     if (ArkNativeEngine::napiProfilerEnabled) {
504         FinishTrace(HITRACE_TAG_ACE);
505     }
506 #endif
507 }
508 
GetArgc() const509 size_t NapiNativeCallbackInfo::GetArgc() const
510 {
511     return static_cast<size_t>(info->GetArgsNumber());
512 }
513 
GetArgv(napi_value * argv,size_t argc)514 size_t NapiNativeCallbackInfo::GetArgv(napi_value* argv, size_t argc)
515 {
516     auto *vm = info->GetVM();
517     if (argc > 0) {
518         size_t i = 0;
519         size_t buffer = GetArgc();
520         for (; i < buffer && i < argc; i++) {
521             panda::Local<panda::JSValueRef> value = info->GetCallArgRef(i);
522             if (value->IsFunction()) {
523                 FunctionSetContainerId(vm, value);
524             }
525             argv[i] = JsValueFromLocalValue(value);
526         }
527         return i;
528     }
529 
530     return GetArgc();
531 }
532 
GetThisVar()533 napi_value NapiNativeCallbackInfo::GetThisVar()
534 {
535     return JsValueFromLocalValue(info->GetThisRef());
536 }
537 
GetFunction()538 napi_value NapiNativeCallbackInfo::GetFunction()
539 {
540     auto *vm = info->GetVM();
541     panda::Local<panda::JSValueRef> newValue = info->GetNewTargetRef();
542     if (newValue->IsFunction()) {
543         FunctionSetContainerId(vm, newValue);
544     }
545 
546     return JsValueFromLocalValue(newValue);
547 }
548 
GetFunctionInfo()549 NapiFunctionInfo* NapiNativeCallbackInfo::GetFunctionInfo()
550 {
551     return reinterpret_cast<NapiFunctionInfo*>(info->GetData());
552 }
553 
ArkNativeFunctionCallBack(JsiRuntimeCallInfo * runtimeInfo)554 panda::JSValueRef ArkNativeFunctionCallBack(JsiRuntimeCallInfo *runtimeInfo)
555 {
556     EcmaVM *vm = runtimeInfo->GetVM();
557     panda::LocalScope scope(vm);
558     bool getStackBeforeCallNapiSuccess = false;
559     JSNApi::GetStackBeforeCallNapiSuccess(vm, getStackBeforeCallNapiSuccess);
560     auto info = reinterpret_cast<NapiFunctionInfo*>(runtimeInfo->GetData());
561     auto engine = reinterpret_cast<NativeEngine*>(info->env);
562     auto cb = info->callback;
563     if (engine == nullptr) {
564         HILOG_ERROR("native engine is null");
565         return **JSValueRef::Undefined(vm);
566     }
567 
568     NapiNativeCallbackInfo cbInfo(runtimeInfo);
569     StartNapiProfilerTrace(runtimeInfo);
570 
571     if (JSNApi::IsMixedDebugEnabled(vm)) {
572         JSNApi::NotifyNativeCalling(vm, reinterpret_cast<void *>(cb));
573     }
574 
575     napi_value result = nullptr;
576     if (cb != nullptr) {
577         result = cb(info->env, &cbInfo);
578     }
579 
580     if (JSNApi::IsMixedDebugEnabled(vm)) {
581         JSNApi::NotifyNativeReturn(vm, reinterpret_cast<void *>(cb));
582     }
583 
584     Local<panda::JSValueRef> localRet = panda::JSValueRef::Undefined(vm);
585     if (result != nullptr) {
586         localRet = LocalValueFromJsValue(result);
587     }
588 
589     FinishNapiProfilerTrace();
590     // Fixme: Rethrow error to engine while clear lastException_
591     if (!engine->lastException_.IsEmpty()) {
592         engine->lastException_.Empty();
593     }
594 
595     if (localRet.IsEmpty()) {
596         return **JSValueRef::Undefined(vm);
597     }
598     if (getStackBeforeCallNapiSuccess) {
599         JSNApi::GetStackAfterCallNapi(vm);
600     }
601     return **localRet;
602 }
603 
NapiNativeCreateFunction(napi_env env,const char * name,NapiNativeCallback cb,void * value)604 Local<panda::JSValueRef> NapiNativeCreateFunction(napi_env env, const char* name, NapiNativeCallback cb, void* value)
605 {
606     auto engine = reinterpret_cast<NativeEngine*>(env);
607     auto vm = const_cast<EcmaVM*>(engine->GetEcmaVm());
608     NapiFunctionInfo* funcInfo = NapiFunctionInfo::CreateNewInstance();
609     if (funcInfo == nullptr) {
610         HILOG_ERROR("funcInfo is nullptr");
611         return JSValueRef::Undefined(vm);
612     }
613     funcInfo->env = env;
614     funcInfo->callback = cb;
615     funcInfo->data = value;
616 
617     Local<panda::FunctionRef> fn = panda::FunctionRef::New(vm, ArkNativeFunctionCallBack,
618                                                            [](void* externalPointer, void* data) {
619                                                                 auto info = reinterpret_cast<NapiFunctionInfo*>(data);
620                                                                 if (info != nullptr) {
621                                                                     delete info;
622                                                                 }
623                                                            },
624                                                            reinterpret_cast<void*>(funcInfo), true);
625     Local<panda::StringRef> fnName = panda::StringRef::NewFromUtf8(vm, name);
626     fn->SetName(vm, fnName);
627     return fn;
628 }
629 
GetProperty(EcmaVM * vm,Local<panda::ObjectRef> & obj,const char * name)630 Local<JSValueRef> GetProperty(EcmaVM* vm, Local<panda::ObjectRef> &obj, const char* name)
631 {
632     Local<StringRef> key = StringRef::NewFromUtf8(vm, name);
633     Local<JSValueRef> val = obj->Get(vm, key);
634     return val;
635 }
636 
GetCString(EcmaVM * vm,Local<StringRef> str,char * buffer,size_t size,size_t * length)637 void GetCString(EcmaVM* vm, Local<StringRef> str, char* buffer, size_t size, size_t* length)
638 {
639     if (length == nullptr) {
640         return;
641     }
642     if (buffer == nullptr) {
643         *length = str->Utf8Length(vm) - 1;
644     } else if (size != 0) {
645         int copied = str->WriteUtf8(buffer, size - 1, true) - 1;
646         buffer[copied] = '\0';
647         *length = copied;
648     } else {
649         *length = 0;
650     }
651 }
652 
NapiGetModuleName(napi_env env,Local<panda::ObjectRef> & obj)653 std::string NapiGetModuleName(napi_env env, Local<panda::ObjectRef> &obj)
654 {
655     auto engine = reinterpret_cast<NativeEngine*>(env);
656     auto vm = const_cast<EcmaVM*>(engine->GetEcmaVm());
657     std::string moduleName("");
658     auto nativeModuleName = GetProperty(vm, obj, PANDA_MODULE_NAME);
659     if (nativeModuleName->IsString()) {
660         char arrayName[PANDA_MODULE_NAME_LEN] = {0};
661         size_t len = 0;
662         GetCString(vm, nativeModuleName, arrayName, PANDA_MODULE_NAME_LEN, &len);
663         moduleName += arrayName;
664         moduleName += ".";
665     }
666     return moduleName;
667 }
668 
NapiDefineProperty(napi_env env,Local<panda::ObjectRef> & obj,NapiPropertyDescriptor propertyDescriptor)669 bool NapiDefineProperty(napi_env env, Local<panda::ObjectRef> &obj, NapiPropertyDescriptor propertyDescriptor)
670 {
671     auto engine = reinterpret_cast<NativeEngine*>(env);
672     auto vm = engine->GetEcmaVm();
673     bool result = false;
674     Local<panda::JSValueRef> propertyName;
675     if (propertyDescriptor.utf8name != nullptr) {
676         propertyName = panda::StringRef::NewFromUtf8(vm, propertyDescriptor.utf8name);
677     } else {
678         propertyName = LocalValueFromJsValue(propertyDescriptor.name);
679     }
680 
681     bool writable = (propertyDescriptor.attributes & NATIVE_WRITABLE) != 0;
682     bool enumable = (propertyDescriptor.attributes & NATIVE_ENUMERABLE) != 0;
683     bool configable = (propertyDescriptor.attributes & NATIVE_CONFIGURABLE) != 0;
684 
685     std::string fullName("");
686     if (propertyDescriptor.getter != nullptr || propertyDescriptor.setter != nullptr) {
687 #ifdef ENABLE_HITRACE
688         fullName += NapiGetModuleName(env, obj);
689 #endif
690         Local<panda::JSValueRef> localGetter = panda::JSValueRef::Undefined(vm);
691         Local<panda::JSValueRef> localSetter = panda::JSValueRef::Undefined(vm);
692 
693         if (propertyDescriptor.getter != nullptr) {
694             fullName += "getter";
695             localGetter = NapiNativeCreateFunction(env, fullName.c_str(),
696                                                    propertyDescriptor.getter, propertyDescriptor.data);
697         }
698         if (propertyDescriptor.setter != nullptr) {
699             fullName += "setter";
700             localSetter = NapiNativeCreateFunction(env, fullName.c_str(),
701                                                    propertyDescriptor.setter, propertyDescriptor.data);
702         }
703 
704         PropertyAttribute attr(panda::JSValueRef::Undefined(vm), false, enumable, configable);
705         result = obj->SetAccessorProperty(vm, propertyName, localGetter, localSetter, attr);
706     } else if (propertyDescriptor.method != nullptr) {
707 #ifdef ENABLE_HITRACE
708         fullName += NapiGetModuleName(env, obj);
709 #endif
710         if (propertyDescriptor.utf8name != nullptr) {
711             fullName += propertyDescriptor.utf8name;
712         } else {
713             fullName += propertyName->IsString()
714                         ? Local<panda::StringRef>(propertyName)->ToString()
715                         : Local<panda::SymbolRef>(propertyName)->GetDescription(vm)->ToString();
716         }
717         Local<panda::JSValueRef> cbObj = NapiNativeCreateFunction(env, fullName.c_str(),
718                                                                   propertyDescriptor.method, propertyDescriptor.data);
719         PropertyAttribute attr(cbObj, writable, enumable, configable);
720         result = obj->DefineProperty(vm, propertyName, attr);
721     } else {
722         Local<panda::JSValueRef> val = LocalValueFromJsValue(propertyDescriptor.value);
723 
724         PropertyAttribute attr(val, writable, enumable, configable);
725         result = obj->DefineProperty(vm, propertyName, attr);
726     }
727     Local<panda::ObjectRef> excep = panda::JSNApi::GetUncaughtException(vm);
728     if (!excep.IsNull()) {
729         HILOG_DEBUG("ArkNativeObject::DefineProperty occur Exception");
730         panda::JSNApi::GetAndClearUncaughtException(vm);
731     }
732     return result;
733 }
734 
NapiCreateObjectWithProperties(napi_env env,size_t propertyCount,const napi_property_descriptor * properties,Local<panda::JSValueRef> * keys,PropertyAttribute * attrs)735 panda::Local<panda::ObjectRef> NapiCreateObjectWithProperties(napi_env env, size_t propertyCount,
736                                                               const napi_property_descriptor *properties,
737                                                               Local<panda::JSValueRef> *keys,
738                                                               PropertyAttribute *attrs)
739 {
740     auto vm = reinterpret_cast<NativeEngine*>(env)->GetEcmaVm();
741     panda::EscapeLocalScope scope(vm);
742     for (size_t i = 0; i < propertyCount; ++i) {
743         const napi_property_descriptor &property = properties[i];
744 
745         const char* utf8name = property.utf8name;
746         uint32_t attributes = property.attributes;
747         bool writable = (attributes & NATIVE_WRITABLE) != 0;
748         bool enumable = (attributes & NATIVE_ENUMERABLE) != 0;
749         bool configable = (attributes & NATIVE_CONFIGURABLE) != 0;
750         NapiNativeCallback method = reinterpret_cast<NapiNativeCallback>(property.method);
751         NapiNativeCallback getter = reinterpret_cast<NapiNativeCallback>(property.getter);
752         NapiNativeCallback setter = reinterpret_cast<NapiNativeCallback>(property.setter);
753         napi_value value = property.value;
754         void *data = property.data;
755 
756         Local<panda::JSValueRef> val = panda::JSValueRef::Undefined(vm);
757 
758         std::string fullName("");
759         if (getter != nullptr || setter != nullptr) {
760             Local<panda::JSValueRef> localGetter = panda::JSValueRef::Undefined(vm);
761             Local<panda::JSValueRef> localSetter = panda::JSValueRef::Undefined(vm);
762 
763             if (getter != nullptr) {
764                 fullName += "getter";
765                 localGetter = NapiNativeCreateFunction(env, fullName.c_str(), getter, data);
766             }
767             if (setter != nullptr) {
768                 fullName += "setter";
769                 localSetter = NapiNativeCreateFunction(env, fullName.c_str(), setter, data);
770             }
771 
772             val = panda::ObjectRef::CreateAccessorData(vm, localGetter, localSetter);
773             writable = false;
774         } else if (method != nullptr) {
775             fullName += utf8name;
776             val = NapiNativeCreateFunction(env, fullName.c_str(), method, data);
777         } else {
778             val = LocalValueFromJsValue(value);
779         }
780         new (reinterpret_cast<void *>(&attrs[i])) PropertyAttribute(val, writable, enumable, configable);
781         keys[i] = panda::StringRef::NewFromUtf8(vm, utf8name);
782     }
783     Local<panda::ObjectRef> object = panda::ObjectRef::NewWithProperties(vm, propertyCount, keys, attrs);
784     return scope.Escape(object);
785 }
786 
GetModuleFromName(const std::string & moduleName,bool isAppModule,const std::string & id,const std::string & param,const std::string & instanceName,void ** instance)787 panda::Local<panda::ObjectRef> ArkNativeEngine::GetModuleFromName(
788     const std::string& moduleName, bool isAppModule, const std::string& id, const std::string& param,
789     const std::string& instanceName, void** instance)
790 {
791     panda::EscapeLocalScope scope(vm_);
792     Local<ObjectRef> exports(JSValueRef::Undefined(vm_));
793     NativeModuleManager* moduleManager = NativeModuleManager::GetInstance();
794     NativeModule* module = moduleManager->LoadNativeModule(moduleName.c_str(), nullptr, isAppModule);
795     if (module != nullptr) {
796         Local<StringRef> idStr = StringRef::NewFromUtf8(vm_, id.c_str(), id.size());
797         napi_value idValue = JsValueFromLocalValue(idStr);
798         Local<StringRef> paramStr = StringRef::NewFromUtf8(vm_, param.c_str(), param.size());
799         napi_value paramValue = JsValueFromLocalValue(paramStr);
800         Local<ObjectRef> exportObj = ObjectRef::New(vm_);
801         NapiPropertyDescriptor idProperty, paramProperty;
802         idProperty.utf8name = "id";
803         idProperty.value = idValue;
804         paramProperty.utf8name = "param";
805         paramProperty.value = paramValue;
806         SetModuleName(exportObj, module->name);
807         NapiDefineProperty(reinterpret_cast<napi_env>(this), exportObj, idProperty);
808         NapiDefineProperty(reinterpret_cast<napi_env>(this), exportObj, paramProperty);
809         MoudleNameLocker nameLocker(module->name);
810         module->registerCallback(reinterpret_cast<napi_env>(this), JsValueFromLocalValue(exportObj));
811         napi_value nExport = JsValueFromLocalValue(exportObj);
812         napi_value exportInstance = nullptr;
813         napi_status status = napi_get_named_property(
814             reinterpret_cast<napi_env>(this), nExport, instanceName.c_str(), &exportInstance);
815         if (status != napi_ok) {
816             HILOG_ERROR("GetModuleFromName napi_get_named_property status != napi_ok");
817         }
818 
819         status = napi_unwrap(reinterpret_cast<napi_env>(this), exportInstance, reinterpret_cast<void**>(instance));
820         if (status != napi_ok) {
821             HILOG_ERROR("GetModuleFromName napi_unwrap status != napi_ok");
822         }
823         exports = exportObj;
824     }
825     return scope.Escape(exports);
826 }
827 
CreatePromise(NativeDeferred ** deferred)828 napi_value ArkNativeEngine::CreatePromise(NativeDeferred** deferred)
829 {
830     panda::EscapeLocalScope scope(vm_);
831     Local<PromiseCapabilityRef> capability = PromiseCapabilityRef::New(vm_);
832     *deferred = new ArkNativeDeferred(this, capability);
833     Local<JSValueRef> promiseValue = capability->GetPromise(vm_);
834     return JsValueFromLocalValue(scope.Escape(promiseValue));
835 }
836 
LoadModuleByName(const std::string & moduleName,bool isAppModule,const std::string & param,const std::string & instanceName,void * instance,const std::string & path)837 panda::Local<panda::ObjectRef> ArkNativeEngine::LoadModuleByName(const std::string& moduleName, bool isAppModule,
838     const std::string& param, const std::string& instanceName, void* instance, const std::string& path)
839 {
840     panda::EscapeLocalScope scope(vm_);
841     Local<ObjectRef> exports(JSValueRef::Undefined(vm_));
842     NativeModuleManager* moduleManager = NativeModuleManager::GetInstance();
843     NativeModule* module =
844         moduleManager->LoadNativeModule(moduleName.c_str(), path.empty() ? nullptr : path.c_str(), isAppModule);
845     if (module != nullptr) {
846         Local<ObjectRef> exportObj = ObjectRef::New(vm_);
847         NapiPropertyDescriptor paramProperty, instanceProperty;
848         Local<StringRef> paramStr = StringRef::NewFromUtf8(vm_, param.c_str(), param.size());
849         napi_value paramValue = JsValueFromLocalValue(paramStr);
850         paramProperty.utf8name = "param";
851         paramProperty.value = paramValue;
852         Local<ObjectRef> instanceValue = ObjectRef::New(vm_);
853         Local<StringRef> key = StringRef::GetNapiWrapperString(vm_);
854         if (instance == nullptr && instanceValue->Has(vm_, key)) {
855             Local<ObjectRef> wrapper = instanceValue->Get(vm_, key);
856             auto ref = reinterpret_cast<NativeReference*>(wrapper->GetNativePointerField(0));
857             wrapper->SetNativePointerField(vm_, 0, nullptr, nullptr, nullptr, 0);
858             instanceValue->Delete(vm_, key);
859             delete ref;
860         } else {
861             Local<ObjectRef> object = ObjectRef::New(vm_);
862             NativeReference* ref = nullptr;
863             Local<JSValueRef> value(instanceValue);
864             ref = new ArkNativeReference(this, vm_, value, 0, true, nullptr, instance, nullptr);
865 
866             object->SetNativePointerFieldCount(vm_, 1);
867             object->SetNativePointerField(vm_, 0, ref, nullptr, nullptr, 0);
868             PropertyAttribute attr(object, true, false, true);
869             instanceValue->DefineProperty(vm_, key, attr);
870         }
871         instanceProperty.utf8name = instanceName.c_str();
872         instanceProperty.value = JsValueFromLocalValue(instanceValue);
873         SetModuleName(exportObj, module->name);
874         NapiDefineProperty(reinterpret_cast<napi_env>(this), exportObj, paramProperty);
875         NapiDefineProperty(reinterpret_cast<napi_env>(this), exportObj, instanceProperty);
876 
877         MoudleNameLocker nameLocker(module->name);
878         module->registerCallback(reinterpret_cast<napi_env>(this), JsValueFromLocalValue(exportObj));
879         exports = exportObj;
880     }
881     return scope.Escape(exports);
882 }
883 
Loop(LoopMode mode,bool needSync)884 void ArkNativeEngine::Loop(LoopMode mode, bool needSync)
885 {
886     LocalScope scope(vm_);
887     NativeEngine::Loop(mode, needSync);
888     panda::JSNApi::ExecutePendingJob(vm_);
889 }
890 
SetModuleName(Local<ObjectRef> & nativeObj,std::string moduleName)891 void ArkNativeEngine::SetModuleName(Local<ObjectRef> &nativeObj, std::string moduleName)
892 {
893 #ifdef ENABLE_HITRACE
894     if (ArkNativeEngine::napiProfilerEnabled) {
895         Local<StringRef> moduleNameStr = StringRef::NewFromUtf8(vm_, moduleName.c_str(), moduleName.size());
896         Local<StringRef> key = StringRef::NewFromUtf8(vm_, PANDA_MODULE_NAME);
897         nativeObj->Set(vm_, key, moduleNameStr);
898     }
899 #endif
900 }
901 
ConcurrentCallbackFunc(Local<JSValueRef> result,bool success,void * taskInfo,void * data)902 static void ConcurrentCallbackFunc(Local<JSValueRef> result, bool success, void *taskInfo, void *data)
903 {
904     if (data == nullptr) {
905         return;
906     }
907     auto engine = static_cast<ArkNativeEngine *>(data);
908     auto concurrentCallbackFunc = engine->GetConcurrentCallbackFunc();
909     if (concurrentCallbackFunc == nullptr) {
910         return;
911     }
912     napi_env env = reinterpret_cast<napi_env>(engine);
913     concurrentCallbackFunc(env, ArkNativeEngine::ArkValueToNapiValue(env, result), success, taskInfo);
914 }
915 
InitTaskPoolThread(NativeEngine * engine,NapiConcurrentCallback callback)916 bool ArkNativeEngine::InitTaskPoolThread(NativeEngine* engine, NapiConcurrentCallback callback)
917 {
918     concurrentCallbackFunc_ = callback;
919     return JSNApi::InitForConcurrentThread(vm_, ConcurrentCallbackFunc, static_cast<void *>(this));
920 }
921 
InitTaskPoolThread(napi_env env,NapiConcurrentCallback callback)922 bool ArkNativeEngine::InitTaskPoolThread(napi_env env, NapiConcurrentCallback callback)
923 {
924     concurrentCallbackFunc_ = callback;
925     return JSNApi::InitForConcurrentThread(vm_, ConcurrentCallbackFunc, static_cast<void *>(this));
926 }
927 
InitTaskPoolFunc(napi_env env,napi_value func,void * taskInfo)928 bool ArkNativeEngine::InitTaskPoolFunc(napi_env env, napi_value func, void* taskInfo)
929 {
930     LocalScope scope(vm_);
931     Local<JSValueRef> function = LocalValueFromJsValue(func);
932     return JSNApi::InitForConcurrentFunction(vm_, function, taskInfo);
933 }
934 
HasPendingJob() const935 bool ArkNativeEngine::HasPendingJob() const
936 {
937     return JSNApi::HasPendingJob(vm_);
938 }
939 
IsProfiling() const940 bool ArkNativeEngine::IsProfiling() const
941 {
942     return JSNApi::IsProfiling(vm_);
943 }
944 
IsExecutingPendingJob() const945 bool ArkNativeEngine::IsExecutingPendingJob() const
946 {
947     return panda::JSNApi::IsExecutingPendingJob(vm_);
948 }
949 
GetCurrentTaskInfo() const950 void* ArkNativeEngine::GetCurrentTaskInfo() const
951 {
952     return JSNApi::GetCurrentTaskInfo(vm_);
953 }
954 
TerminateExecution() const955 void ArkNativeEngine::TerminateExecution() const
956 {
957     DFXJSNApi::TerminateExecution(vm_);
958 }
959 
CallFunction(napi_value thisVar,napi_value function,napi_value const * argv,size_t argc)960 napi_value ArkNativeEngine::CallFunction(
961     napi_value thisVar, napi_value function, napi_value const* argv, size_t argc)
962 {
963     if (function == nullptr) {
964         return nullptr;
965     }
966     panda::EscapeLocalScope scope(vm_);
967     Local<JSValueRef> thisObj = JSValueRef::Undefined(vm_);
968     if (thisVar != nullptr) {
969         thisObj = LocalValueFromJsValue(thisVar);
970     }
971     Local<FunctionRef> funcObj = LocalValueFromJsValue(function);
972     std::vector<Local<JSValueRef>> args;
973     args.reserve(argc);
974     for (size_t i = 0; i < argc; i++) {
975         if (argv[i] != nullptr) {
976             args.emplace_back(LocalValueFromJsValue(argv[i]));
977         } else {
978             args.emplace_back(JSValueRef::Undefined(vm_));
979         }
980     }
981 
982     Local<JSValueRef> value = funcObj->Call(vm_, thisObj, args.data(), argc);
983     if (panda::JSNApi::HasPendingException(vm_)) {
984         HILOG_ERROR("pending exception when js function called");
985         HILOG_ERROR("print exception info: ");
986         panda::JSNApi::PrintExceptionInfo(vm_);
987         return nullptr;
988     }
989 
990     return JsValueFromLocalValue(scope.Escape(value));
991 }
992 
RunScriptPath(const char * path)993 bool ArkNativeEngine::RunScriptPath(const char* path)
994 {
995     panda::JSExecutionScope executionScope(vm_);
996     LocalScope scope(vm_);
997     [[maybe_unused]] bool ret = panda::JSNApi::Execute(vm_, path, PANDA_MAIN_FUNCTION);
998     if (panda::JSNApi::HasPendingException(vm_)) {
999         HandleUncaughtException();
1000         return false;
1001     }
1002     return true;
1003 }
1004 
1005 /*
1006  * Before: input: 1. @ohos.hilog
1007                   2. @system.app (NATIVE_MODULE contains this name)
1008  * After: return: 1.@ohos:hilog
1009  *                2.@native:system.app
1010  */
GetOhmurl(const char * str)1011 std::string ArkNativeEngine::GetOhmurl(const char* str)
1012 {
1013     std::string path(str);
1014     const std::regex reg("@(ohos|system)\\.(\\S+)");
1015     path.erase(0, path.find_first_not_of(" "));
1016     path.erase(path.find_last_not_of(" ") + 1);
1017     bool ret = std::regex_match(path, reg);
1018     if (!ret) {
1019         HILOG_ERROR("ArkNativeEngine:The module name doesn't comply with the naming rules");
1020         return "";
1021     }
1022     std::string systemModule = path.substr(1);
1023     if (NATIVE_MODULE.count(systemModule)) {
1024         return NATIVE_MODULE_PREFIX + systemModule;
1025     } else {
1026         int pos = static_cast<int>(path.find('.'));
1027         std::string systemKey = path.substr(pos + 1, systemModule.size());
1028         return OHOS_MODULE_PREFIX + systemKey;
1029     }
1030 }
1031 
NapiLoadModule(const char * str)1032 napi_value ArkNativeEngine::NapiLoadModule(const char* str)
1033 {
1034     if (str == nullptr) {
1035         HILOG_ERROR("ArkNativeEngine:The module name is empty");
1036         return nullptr;
1037     }
1038     std::string key = GetOhmurl(str);
1039     if (key.size() == 0) {
1040         return nullptr;
1041     }
1042     panda::EscapeLocalScope scope(vm_);
1043     Local<ObjectRef> exportObj = panda::JSNApi::ExecuteNativeModule(vm_, key);
1044     if (exportObj->IsNull()) {
1045         HILOG_ERROR("ArkNativeEngine:napi load module failed");
1046         return nullptr;
1047     }
1048     return JsValueFromLocalValue(scope.Escape(exportObj));
1049 }
1050 
SuspendVMById(uint32_t tid)1051 bool ArkNativeEngine::SuspendVMById(uint32_t tid)
1052 {
1053 #if !defined(PREVIEW) && !defined(IOS_PLATFORM)
1054     return DFXJSNApi::SuspendVMById(vm_, tid);
1055 #else
1056     HILOG_WARN("ARK does not support dfx on windows");
1057     return false;
1058 #endif
1059 }
1060 
ResumeVMById(uint32_t tid)1061 void ArkNativeEngine::ResumeVMById(uint32_t tid)
1062 {
1063 #if !defined(PREVIEW) && !defined(IOS_PLATFORM)
1064     DFXJSNApi::ResumeVMById(vm_, tid);
1065 #else
1066     HILOG_WARN("ARK does not support dfx on windows");
1067     return;
1068 #endif
1069 }
1070 
1071 // The security interface needs to be modified accordingly.
RunScriptBuffer(const char * path,std::vector<uint8_t> & buffer,bool isBundle)1072 napi_value ArkNativeEngine::RunScriptBuffer(const char* path, std::vector<uint8_t>& buffer, bool isBundle)
1073 {
1074     panda::EscapeLocalScope scope(vm_);
1075     [[maybe_unused]] bool ret = false;
1076     if (isBundle) {
1077         ret = panda::JSNApi::Execute(vm_, buffer.data(), buffer.size(), PANDA_MAIN_FUNCTION, path);
1078     } else {
1079         ret = panda::JSNApi::ExecuteModuleBuffer(vm_, buffer.data(), buffer.size(), path);
1080     }
1081 
1082     if (panda::JSNApi::HasPendingException(vm_)) {
1083         HandleUncaughtException();
1084         return nullptr;
1085     }
1086     Local<JSValueRef> undefObj = JSValueRef::Undefined(vm_);
1087     return JsValueFromLocalValue(scope.Escape(undefObj));
1088 }
1089 
RunScriptBuffer(const std::string & path,uint8_t * buffer,size_t size,bool isBundle)1090 bool ArkNativeEngine::RunScriptBuffer(const std::string& path, uint8_t* buffer, size_t size, bool isBundle)
1091 {
1092     panda::JSExecutionScope executionScope(vm_);
1093     LocalScope scope(vm_);
1094     bool ret = false;
1095     if (isBundle) {
1096         ret = panda::JSNApi::ExecuteSecure(vm_, buffer, size, PANDA_MAIN_FUNCTION, path);
1097     } else {
1098         ret = panda::JSNApi::ExecuteModuleBufferSecure(vm_, buffer, size, path);
1099     }
1100 
1101     if (panda::JSNApi::HasPendingException(vm_)) {
1102         HandleUncaughtException();
1103         return false;
1104     }
1105     return ret;
1106 }
1107 
SetPackagePath(const std::string appLibPathKey,const std::vector<std::string> & packagePath)1108 void ArkNativeEngine::SetPackagePath(const std::string appLibPathKey, const std::vector<std::string>& packagePath)
1109 {
1110     auto moduleManager = NativeModuleManager::GetInstance();
1111     if (moduleManager && !packagePath.empty()) {
1112         moduleManager->SetAppLibPath(appLibPathKey, packagePath);
1113     }
1114 }
1115 
CreateInstance(napi_value constructor,napi_value const * argv,size_t argc)1116 napi_value ArkNativeEngine::CreateInstance(napi_value constructor, napi_value const *argv, size_t argc)
1117 {
1118     if (constructor == nullptr) {
1119         return nullptr;
1120     }
1121     panda::EscapeLocalScope scope(vm_);
1122     Local<FunctionRef> value = LocalValueFromJsValue(constructor);
1123     std::vector<Local<JSValueRef>> args;
1124     args.reserve(argc);
1125     for (size_t i = 0; i < argc; i++) {
1126         if (argv[i] != nullptr) {
1127             args.emplace_back(LocalValueFromJsValue(argv[i]));
1128         } else {
1129             args.emplace_back(JSValueRef::Undefined(vm_));
1130         }
1131     }
1132     Local<JSValueRef> instance = value->Constructor(vm_, args.data(), argc);
1133     Local<ObjectRef> excep = panda::JSNApi::GetUncaughtException(vm_);
1134     if (!excep.IsNull()) {
1135         HILOG_ERROR("ArkNativeEngineImpl::CreateInstance occur Exception");
1136         return nullptr;
1137     }
1138     return JsValueFromLocalValue(scope.Escape(instance));
1139 }
1140 
CreateReference(napi_value value,uint32_t initialRefcount,bool flag,NapiNativeFinalize callback,void * data,void * hint)1141 NativeReference* ArkNativeEngine::CreateReference(napi_value value, uint32_t initialRefcount,
1142     bool flag, NapiNativeFinalize callback, void* data, void* hint)
1143 {
1144     return new ArkNativeReference(this, this->GetEcmaVm(), value, initialRefcount, flag, callback, data, hint);
1145 }
1146 
CreateRuntimeFunc(NativeEngine * engine,void * jsEngine,bool isLimitedWorker)1147 NativeEngine* ArkNativeEngine::CreateRuntimeFunc(NativeEngine* engine, void* jsEngine, bool isLimitedWorker)
1148 {
1149     panda::RuntimeOption option;
1150 #if defined(OHOS_PLATFORM) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
1151     int arkProperties = OHOS::system::GetIntParameter<int>("persist.ark.properties", -1);
1152     std::string bundleName = OHOS::system::GetParameter("persist.ark.arkbundlename", "");
1153     size_t gcThreadNum = OHOS::system::GetUintParameter<size_t>("persist.ark.gcthreads", 7);
1154     size_t longPauseTime = OHOS::system::GetUintParameter<size_t>("persist.ark.longpausetime", 40);
1155     bool asmInterpreterEnabled = OHOS::system::GetBoolParameter("persist.ark.asminterpreter", true);
1156     std::string asmOpcodeDisableRange = OHOS::system::GetParameter("persist.ark.asmopcodedisablerange", "");
1157     bool builtinsLazyEnabled = OHOS::system::GetBoolParameter("persist.ark.enablebuiltinslazy", true);
1158     option.SetEnableBuiltinsLazy(builtinsLazyEnabled);
1159     option.SetArkProperties(arkProperties);
1160     option.SetArkBundleName(bundleName);
1161     option.SetGcThreadNum(gcThreadNum);
1162     option.SetLongPauseTime(longPauseTime);
1163     option.SetEnableAsmInterpreter(asmInterpreterEnabled);
1164     option.SetAsmOpcodeDisableRange(asmOpcodeDisableRange);
1165     option.SetIsWorker();
1166     HILOG_DEBUG("ArkNativeEngineImpl::CreateRuntimeFunc ark properties = %{public}d, bundlename = %{public}s",
1167         arkProperties, bundleName.c_str());
1168 #endif
1169     option.SetGcType(panda::RuntimeOption::GC_TYPE::GEN_GC);
1170     const int64_t poolSize = 0x1000000;
1171     option.SetGcPoolSize(poolSize);
1172 #if !defined(PREVIEW) && !defined(IOS_PLATFORM)
1173     option.SetLogLevel(panda::RuntimeOption::LOG_LEVEL::INFO);
1174 #endif
1175     option.SetDebuggerLibraryPath("");
1176     EcmaVM* vm = panda::JSNApi::CreateJSVM(option);
1177     if (vm == nullptr) {
1178         return nullptr;
1179     }
1180     // worker adaptation mergeabc
1181     const panda::ecmascript::EcmaVM* hostVM = reinterpret_cast<ArkNativeEngine*>(engine)->GetEcmaVm();
1182     panda::JSNApi::SynchronizVMInfo(vm, hostVM);
1183     ArkNativeEngine* arkEngine = new ArkNativeEngine(vm, jsEngine, isLimitedWorker);
1184     // init callback
1185     arkEngine->RegisterWorkerFunction(engine);
1186     arkEngine->SetHostEngine(engine);
1187 
1188     auto cleanEnv = [vm]() {
1189         if (vm != nullptr) {
1190             HILOG_DEBUG("cleanEnv is called");
1191             panda::JSNApi::DestroyJSVM(vm);
1192         }
1193     };
1194     arkEngine->SetCleanEnv(cleanEnv);
1195 
1196     if (hostVM != nullptr) {
1197         panda::JSNApi::AddWorker(const_cast<EcmaVM*>(hostVM), vm);
1198     }
1199     return arkEngine;
1200 }
1201 
CreateRuntime(bool isLimitedWorker)1202 void* ArkNativeEngine::CreateRuntime(bool isLimitedWorker)
1203 {
1204     return ArkNativeEngine::CreateRuntimeFunc(this, jsEngine_, isLimitedWorker);
1205 }
1206 
StartCpuProfiler(const std::string & fileName)1207 void ArkNativeEngine::StartCpuProfiler(const std::string& fileName)
1208 {
1209     JSNApi::SetNativePtrGetter(vm_, reinterpret_cast<void*>(ArkNativeEngine::GetNativePtrCallBack));
1210     DFXJSNApi::StartCpuProfilerForFile(vm_, fileName);
1211 }
1212 
StopCpuProfiler()1213 void ArkNativeEngine::StopCpuProfiler()
1214 {
1215     DFXJSNApi::StopCpuProfilerForFile(vm_);
1216     JSNApi::SetNativePtrGetter(vm_, nullptr);
1217 }
1218 
ResumeVM()1219 void ArkNativeEngine::ResumeVM()
1220 {
1221     DFXJSNApi::ResumeVM(vm_);
1222 }
1223 
SuspendVM()1224 bool ArkNativeEngine::SuspendVM()
1225 {
1226     return DFXJSNApi::SuspendVM(vm_);
1227 }
1228 
IsSuspended()1229 bool ArkNativeEngine::IsSuspended()
1230 {
1231     return DFXJSNApi::IsSuspended(vm_);
1232 }
1233 
CheckSafepoint()1234 bool ArkNativeEngine::CheckSafepoint()
1235 {
1236     return DFXJSNApi::CheckSafepoint(vm_);
1237 }
1238 
RunBufferScript(std::vector<uint8_t> & buffer)1239 napi_value ArkNativeEngine::RunBufferScript(std::vector<uint8_t>& buffer)
1240 {
1241     panda::EscapeLocalScope scope(vm_);
1242     [[maybe_unused]] bool ret = panda::JSNApi::Execute(vm_, buffer.data(), buffer.size(), PANDA_MAIN_FUNCTION);
1243 
1244     if (panda::JSNApi::HasPendingException(vm_)) {
1245         HandleUncaughtException();
1246         return nullptr;
1247     }
1248     Local<JSValueRef> undefObj = JSValueRef::Undefined(vm_);
1249     return JsValueFromLocalValue(scope.Escape(undefObj));
1250 }
1251 
RunActor(std::vector<uint8_t> & buffer,const char * descriptor,char * entryPoint)1252 napi_value ArkNativeEngine::RunActor(std::vector<uint8_t>& buffer, const char* descriptor, char* entryPoint)
1253 {
1254     panda::EscapeLocalScope scope(vm_);
1255     std::string desc(descriptor);
1256     [[maybe_unused]] bool ret = false;
1257     if (panda::JSNApi::IsBundle(vm_)) {
1258         ret = panda::JSNApi::Execute(vm_, buffer.data(), buffer.size(), PANDA_MAIN_FUNCTION, desc);
1259     } else if (!buffer.empty()) {
1260         if (entryPoint == nullptr) {
1261             HILOG_DEBUG("Input entryPoint is nullptr, please input entryPoint for merged ESModule");
1262             // this path for bundle and abc compiled by single module js
1263             ret = panda::JSNApi::Execute(vm_, buffer.data(), buffer.size(), PANDA_MAIN_FUNCTION, desc);
1264         } else {
1265             // this path for mergeabc with specific entryPoint
1266             // entryPoint: bundleName/moduleName/xxx/xxx
1267             panda::JSNApi::SetModuleInfo(vm_, desc, std::string(entryPoint));
1268             ret = panda::JSNApi::Execute(vm_, buffer.data(), buffer.size(), entryPoint, desc);
1269         }
1270     } else {
1271         // this path for worker
1272         ret = panda::JSNApi::Execute(vm_, desc, PANDA_MAIN_FUNCTION);
1273     }
1274 
1275     if (panda::JSNApi::HasPendingException(vm_)) {
1276         HandleUncaughtException();
1277         return nullptr;
1278     }
1279     Local<JSValueRef> undefObj = JSValueRef::Undefined(vm_);
1280     return JsValueFromLocalValue(scope.Escape(undefObj));
1281 }
1282 
GetCurrentModuleInfo(std::string & moduleName,std::string & fileName,bool needRecordName)1283 void ArkNativeEngine::GetCurrentModuleInfo(std::string& moduleName, std::string& fileName, bool needRecordName)
1284 {
1285     LocalScope scope(vm_);
1286     std::pair<std::string, std::string> moduleInfo = panda::JSNApi::GetCurrentModuleInfo(vm_, needRecordName);
1287     moduleName = moduleInfo.first; // if needRecordName is true, then moduleName is recordName.
1288     fileName = moduleInfo.second;
1289 }
1290 
GetIsBundle()1291 bool ArkNativeEngine::GetIsBundle()
1292 {
1293     LocalScope scope(vm_);
1294     return panda::JSNApi::IsBundle(vm_);
1295 }
1296 
LoadArkModule(const void * buffer,int32_t len,const std::string & fileName)1297 panda::Local<panda::ObjectRef> ArkNativeEngine::LoadArkModule(const void* buffer,
1298     int32_t len, const std::string& fileName)
1299 {
1300     panda::EscapeLocalScope scope(vm_);
1301     Local<ObjectRef> undefObj(JSValueRef::Undefined(vm_));
1302     if (buffer == nullptr || len <= 0 || fileName.empty()) {
1303         HILOG_ERROR("fileName is nullptr or source code is nullptr");
1304         return scope.Escape(undefObj);
1305     }
1306 
1307     bool res = JSNApi::ExecuteModuleFromBuffer(vm_, buffer, len, fileName);
1308     if (!res) {
1309         HILOG_ERROR("Execute module failed");
1310         return scope.Escape(undefObj);
1311     }
1312 
1313     Local<ObjectRef> exportObj = JSNApi::GetExportObjectFromBuffer(vm_, fileName, "default");
1314     if (exportObj->IsNull()) {
1315         HILOG_ERROR("Get export object failed");
1316         return scope.Escape(undefObj);
1317     }
1318 
1319     HILOG_DEBUG("ArkNativeEngineImpl::LoadModule end");
1320     return scope.Escape(exportObj);
1321 }
1322 
ValueToNapiValue(JSValueWrapper & value)1323 napi_value ArkNativeEngine::ValueToNapiValue(JSValueWrapper& value)
1324 {
1325     Global<JSValueRef> arkValue = value;
1326     return JsValueFromLocalValue(arkValue.ToLocal(vm_));
1327 }
1328 
ArkValueToNapiValue(napi_env env,Local<JSValueRef> value)1329 napi_value ArkNativeEngine::ArkValueToNapiValue(napi_env env, Local<JSValueRef> value)
1330 {
1331     return JsValueFromLocalValue(value);
1332 }
1333 
GetSourceCodeInfo(napi_value value,ErrorPos pos)1334 std::string ArkNativeEngine::GetSourceCodeInfo(napi_value value, ErrorPos pos)
1335 {
1336     if (value == nullptr || pos.first == 0) {
1337         return "";
1338     }
1339 
1340     LocalScope scope(vm_);
1341     Local<panda::FunctionRef> func = LocalValueFromJsValue(value);
1342     uint32_t line = pos.first;
1343     uint32_t column = pos.second;
1344     Local<panda::StringRef> sourceCode = func->GetSourceCode(vm_, line);
1345     std::string sourceCodeStr = sourceCode->ToString();
1346     if (sourceCodeStr.empty()) {
1347         return "";
1348     }
1349     std::string sourceCodeInfo = "SourceCode:\n";
1350     sourceCodeInfo.append(sourceCodeStr).append("\n");
1351     for (uint32_t k = 0; k < column - 1; k++) {
1352         sourceCodeInfo.push_back(' ');
1353     }
1354     sourceCodeInfo.append("^\n");
1355     return sourceCodeInfo;
1356 }
1357 
ExecuteJsBin(const std::string & fileName)1358 bool ArkNativeEngine::ExecuteJsBin(const std::string& fileName)
1359 {
1360     panda::JSExecutionScope executionScope(vm_);
1361     LocalScope scope(vm_);
1362     bool ret = JSNApi::Execute(vm_, fileName, PANDA_MAIN_FUNCTION);
1363     return ret;
1364 }
1365 
TriggerFatalException(napi_value error)1366 bool ArkNativeEngine::TriggerFatalException(napi_value error)
1367 {
1368     return true;
1369 }
1370 
AdjustExternalMemory(int64_t ChangeInBytes,int64_t * AdjustedValue)1371 bool ArkNativeEngine::AdjustExternalMemory(int64_t ChangeInBytes, int64_t* AdjustedValue)
1372 {
1373     return true;
1374 }
1375 
SetPromiseRejectCallback(NativeReference * rejectCallbackRef,NativeReference * checkCallbackRef)1376 void ArkNativeEngine::SetPromiseRejectCallback(NativeReference* rejectCallbackRef, NativeReference* checkCallbackRef)
1377 {
1378     if (rejectCallbackRef == nullptr || checkCallbackRef == nullptr) {
1379         HILOG_ERROR("rejectCallbackRef or checkCallbackRef is nullptr");
1380         return;
1381     }
1382     promiseRejectCallbackRef_ = rejectCallbackRef;
1383     checkCallbackRef_ = checkCallbackRef;
1384     JSNApi::SetHostPromiseRejectionTracker(vm_, reinterpret_cast<void*>(PromiseRejectCallback),
1385                                            reinterpret_cast<void*>(this));
1386 }
1387 
PromiseRejectCallback(void * info)1388 void ArkNativeEngine::PromiseRejectCallback(void* info)
1389 {
1390     panda::PromiseRejectInfo* promiseRejectInfo = reinterpret_cast<panda::PromiseRejectInfo*>(info);
1391     ArkNativeEngine* env = reinterpret_cast<ArkNativeEngine*>(promiseRejectInfo->GetData());
1392 
1393     if (env == nullptr) {
1394         HILOG_ERROR("engine is nullptr");
1395         return;
1396     }
1397 
1398     if (env->promiseRejectCallbackRef_ == nullptr || env->checkCallbackRef_ == nullptr) {
1399         HILOG_ERROR("promiseRejectCallbackRef or checkCallbackRef is nullptr");
1400         return;
1401     }
1402     panda::ecmascript::EcmaVM* vm = const_cast<EcmaVM*>(env->GetEcmaVm());
1403     LocalScope scope(vm);
1404     Local<JSValueRef> promise = promiseRejectInfo->GetPromise();
1405     Local<JSValueRef> reason = promiseRejectInfo->GetReason();
1406     panda::PromiseRejectInfo::PROMISE_REJECTION_EVENT operation = promiseRejectInfo->GetOperation();
1407 
1408     Local<JSValueRef> type(IntegerRef::New(vm, static_cast<int32_t>(operation)));
1409 
1410     Local<JSValueRef> args[] = {type, promise, reason};
1411 
1412     napi_value promiseNapiRejectCallback = env->promiseRejectCallbackRef_->Get();
1413     Local<FunctionRef> promiseRejectCallback = LocalValueFromJsValue(promiseNapiRejectCallback);
1414     if (!promiseRejectCallback.IsEmpty()) {
1415         promiseRejectCallback->Call(vm, JSValueRef::Undefined(vm), args, 3); // 3 args size
1416     }
1417 
1418     if (operation == panda::PromiseRejectInfo::PROMISE_REJECTION_EVENT::REJECT) {
1419         Local<JSValueRef> checkCallback = LocalValueFromJsValue(env->checkCallbackRef_->Get());
1420         if (!checkCallback.IsEmpty()) {
1421             JSNApi::SetHostEnqueueJob(vm, checkCallback);
1422         }
1423     }
1424 }
1425 
DumpHeapSnapshot(const std::string & path,bool isVmMode,DumpFormat dumpFormat)1426 void ArkNativeEngine::DumpHeapSnapshot(const std::string& path, bool isVmMode, DumpFormat dumpFormat)
1427 {
1428     if (dumpFormat == DumpFormat::JSON) {
1429         DFXJSNApi::DumpHeapSnapshot(vm_, 0, path, isVmMode);
1430     }
1431     if (dumpFormat == DumpFormat::BINARY) {
1432         DFXJSNApi::DumpHeapSnapshot(vm_, 1, path, isVmMode);
1433     }
1434     if (dumpFormat == DumpFormat::OTHER) {
1435         DFXJSNApi::DumpHeapSnapshot(vm_, 2, path, isVmMode); // 2:enum is 2
1436     }
1437 }
1438 
DumpCpuProfile(bool isVmMode,DumpFormat dumpFormat,bool isPrivate,bool isFullGC)1439 void ArkNativeEngine::DumpCpuProfile(bool isVmMode, DumpFormat dumpFormat, bool isPrivate, bool isFullGC)
1440 {
1441     if (dumpFormat == DumpFormat::JSON) {
1442         DFXJSNApi::DumpCpuProfile(vm_, 0, isVmMode, isPrivate, false, isFullGC);
1443     }
1444     if (dumpFormat == DumpFormat::BINARY) {
1445         DFXJSNApi::DumpCpuProfile(vm_, 1, isVmMode, isPrivate);
1446     }
1447     if (dumpFormat == DumpFormat::OTHER) {
1448         DFXJSNApi::DumpCpuProfile(vm_, 2, isVmMode, isPrivate); // 2:enum is 2
1449     }
1450 }
1451 
DumpHeapSnapshot(bool isVmMode,DumpFormat dumpFormat,bool isPrivate,bool isFullGC)1452 void ArkNativeEngine::DumpHeapSnapshot(bool isVmMode, DumpFormat dumpFormat, bool isPrivate, bool isFullGC)
1453 {
1454     if (dumpFormat == DumpFormat::JSON) {
1455         DFXJSNApi::DumpHeapSnapshot(vm_, 0, isVmMode, isPrivate, false, isFullGC);
1456     }
1457     if (dumpFormat == DumpFormat::BINARY) {
1458         DFXJSNApi::DumpHeapSnapshot(vm_, 1, isVmMode, isPrivate);
1459     }
1460     if (dumpFormat == DumpFormat::OTHER) {
1461         DFXJSNApi::DumpHeapSnapshot(vm_, 2, isVmMode, isPrivate); // 2:enum is 2
1462     }
1463 }
1464 
BuildNativeAndJsStackTrace(std::string & stackTraceStr)1465 bool ArkNativeEngine::BuildNativeAndJsStackTrace(std::string& stackTraceStr)
1466 {
1467 #if !defined(PREVIEW) && !defined(IOS_PLATFORM)
1468     return DFXJSNApi::BuildNativeAndJsStackTrace(vm_, stackTraceStr);
1469 #else
1470     HILOG_WARN("ARK does not support dfx on windows");
1471     return false;
1472 #endif
1473 }
1474 
BuildJsStackTrace(std::string & stackTraceStr)1475 bool ArkNativeEngine::BuildJsStackTrace(std::string& stackTraceStr)
1476 {
1477 #if !defined(PREVIEW) && !defined(IOS_PLATFORM)
1478     return DFXJSNApi::BuildJsStackTrace(vm_, stackTraceStr);
1479 #else
1480     HILOG_WARN("ARK does not support dfx on windows");
1481     return false;
1482 #endif
1483 }
1484 
BuildJsStackInfoList(uint32_t tid,std::vector<JsFrameInfo> & jsFrames)1485 bool ArkNativeEngine::BuildJsStackInfoList(uint32_t tid, std::vector<JsFrameInfo>& jsFrames)
1486 {
1487 #if !defined(PREVIEW) && !defined(IOS_PLATFORM)
1488     std::vector<ArkJsFrameInfo> arkJsFrames;
1489     bool sign = DFXJSNApi::BuildJsStackInfoList(vm_, tid, arkJsFrames);
1490     for (auto jf : arkJsFrames) {
1491         struct JsFrameInfo jsframe;
1492         jsframe.fileName = jf.fileName;
1493         jsframe.functionName = jf.functionName;
1494         jsframe.pos = jf.pos;
1495         jsframe.nativePointer = jf.nativePointer;
1496         jsFrames.emplace_back(jsframe);
1497     }
1498     return sign;
1499 #else
1500     HILOG_WARN("ARK does not support dfx on windows");
1501     return false;
1502 #endif
1503 }
1504 
DeleteWorker(NativeEngine * workerEngine)1505 bool ArkNativeEngine::DeleteWorker(NativeEngine* workerEngine)
1506 {
1507     if (workerEngine != nullptr) {
1508 #if !defined(PREVIEW)
1509         const panda::ecmascript::EcmaVM* workerVM = reinterpret_cast<ArkNativeEngine*>(workerEngine)->GetEcmaVm();
1510         if (workerVM != nullptr) {
1511             return panda::JSNApi::DeleteWorker(vm_, const_cast<EcmaVM*>(workerVM));
1512         }
1513 #else
1514         HILOG_WARN("ARK does not support dfx on windows");
1515 #endif
1516         return false;
1517         }
1518     return false;
1519 }
1520 
StartHeapTracking(double timeInterval,bool isVmMode)1521 bool ArkNativeEngine::StartHeapTracking(double timeInterval, bool isVmMode)
1522 {
1523     return DFXJSNApi::StartHeapTracking(vm_, timeInterval, isVmMode);
1524 }
1525 
StopHeapTracking(const std::string & filePath)1526 bool ArkNativeEngine::StopHeapTracking(const std::string &filePath)
1527 {
1528     return DFXJSNApi::StopHeapTracking(vm_, filePath);
1529 }
1530 
1531 #if !defined(PREVIEW)
PrintStatisticResult()1532 void ArkNativeEngine::PrintStatisticResult()
1533 {
1534     DFXJSNApi::PrintStatisticResult(vm_);
1535 }
1536 
StartRuntimeStat()1537 void ArkNativeEngine::StartRuntimeStat()
1538 {
1539     DFXJSNApi::StartRuntimeStat(vm_);
1540 }
1541 
StopRuntimeStat()1542 void ArkNativeEngine::StopRuntimeStat()
1543 {
1544     DFXJSNApi::StopRuntimeStat(vm_);
1545 }
1546 
GetArrayBufferSize()1547 size_t ArkNativeEngine::GetArrayBufferSize()
1548 {
1549     return DFXJSNApi::GetArrayBufferSize(vm_);
1550 }
1551 
GetHeapTotalSize()1552 size_t ArkNativeEngine::GetHeapTotalSize()
1553 {
1554     return DFXJSNApi::GetHeapTotalSize(vm_);
1555 }
1556 
GetHeapUsedSize()1557 size_t ArkNativeEngine::GetHeapUsedSize()
1558 {
1559     return DFXJSNApi::GetHeapUsedSize(vm_);
1560 }
1561 
GetHeapObjectSize()1562 size_t ArkNativeEngine::GetHeapObjectSize()
1563 {
1564     return DFXJSNApi::GetHeapObjectSize(vm_);
1565 }
1566 
GetHeapLimitSize()1567 size_t ArkNativeEngine::GetHeapLimitSize()
1568 {
1569     return DFXJSNApi::GetHeapLimitSize(vm_);
1570 }
1571 
NotifyApplicationState(bool inBackground)1572 void ArkNativeEngine::NotifyApplicationState(bool inBackground)
1573 {
1574     DFXJSNApi::NotifyApplicationState(vm_, inBackground);
1575 }
1576 
NotifyIdleStatusControl(std::function<void (bool)> callback)1577 void ArkNativeEngine::NotifyIdleStatusControl(std::function<void(bool)> callback)
1578 {
1579     DFXJSNApi::NotifyIdleStatusControl(vm_, callback);
1580 }
1581 
NotifyIdleTime(int idleMicroSec)1582 void ArkNativeEngine::NotifyIdleTime(int idleMicroSec)
1583 {
1584     DFXJSNApi::NotifyIdleTime(vm_, idleMicroSec);
1585 }
1586 
NotifyMemoryPressure(bool inHighMemoryPressure)1587 void ArkNativeEngine::NotifyMemoryPressure(bool inHighMemoryPressure)
1588 {
1589     DFXJSNApi::NotifyMemoryPressure(vm_, inHighMemoryPressure);
1590 }
1591 
NotifyForceExpandState(int32_t value)1592 void ArkNativeEngine::NotifyForceExpandState(int32_t value)
1593 {
1594     switch (ForceExpandState(value)) {
1595         case ForceExpandState::FINISH_COLD_START:
1596             DFXJSNApi::NotifyFinishColdStart(vm_, true);
1597             break;
1598         case ForceExpandState::START_HIGH_SENSITIVE:
1599             DFXJSNApi::NotifyHighSensitive(vm_, true);
1600             break;
1601         case ForceExpandState::FINISH_HIGH_SENSITIVE:
1602             DFXJSNApi::NotifyHighSensitive(vm_, false);
1603             break;
1604         default:
1605             HILOG_ERROR("Invalid Force Expand State: %{public}d.", value);
1606             break;
1607     }
1608 }
1609 #else
PrintStatisticResult()1610 void ArkNativeEngine::PrintStatisticResult()
1611 {
1612     HILOG_WARN("ARK does not support dfx on windows");
1613 }
1614 
StartRuntimeStat()1615 void ArkNativeEngine::StartRuntimeStat()
1616 {
1617     HILOG_WARN("ARK does not support dfx on windows");
1618 }
1619 
StopRuntimeStat()1620 void ArkNativeEngine::StopRuntimeStat()
1621 {
1622     HILOG_WARN("ARK does not support dfx on windows");
1623 }
1624 
GetArrayBufferSize()1625 size_t ArkNativeEngine::GetArrayBufferSize()
1626 {
1627     HILOG_WARN("ARK does not support dfx on windows");
1628     return 0;
1629 }
1630 
GetHeapTotalSize()1631 size_t ArkNativeEngine::GetHeapTotalSize()
1632 {
1633     HILOG_WARN("ARK does not support dfx on windows");
1634     return 0;
1635 }
1636 
GetHeapUsedSize()1637 size_t ArkNativeEngine::GetHeapUsedSize()
1638 {
1639     HILOG_WARN("ARK does not support dfx on windows");
1640     return 0;
1641 }
1642 
GetHeapObjectSize()1643 size_t ArkNativeEngine::GetHeapObjectSize()
1644 {
1645     HILOG_WARN("ARK does not support dfx on windows");
1646     return 0;
1647 }
1648 
GetHeapLimitSize()1649 size_t ArkNativeEngine::GetHeapLimitSize()
1650 {
1651     HILOG_WARN("ARK does not support dfx on windows");
1652     return 0;
1653 }
1654 
NotifyApplicationState(bool inBackground)1655 void ArkNativeEngine::NotifyApplicationState([[maybe_unused]] bool inBackground)
1656 {
1657     HILOG_WARN("ARK does not support dfx on windows");
1658 }
1659 
NotifyIdleStatusControl(std::function<void (bool)> callback)1660 void ArkNativeEngine::NotifyIdleStatusControl([[maybe_unused]] std::function<void(bool)> callback)
1661 {
1662     HILOG_WARN("ARK does not support dfx on windows");
1663 }
1664 
NotifyIdleTime(int idleMicroSec)1665 void ArkNativeEngine::NotifyIdleTime([[maybe_unused]] int idleMicroSec)
1666 {
1667     HILOG_WARN("ARK does not support dfx on windows");
1668 }
1669 
NotifyMemoryPressure(bool inHighMemoryPressure)1670 void ArkNativeEngine::NotifyMemoryPressure([[maybe_unused]] bool inHighMemoryPressure)
1671 {
1672     HILOG_WARN("ARK does not support dfx on windows");
1673 }
1674 
NotifyForceExpandState(int32_t value)1675 void ArkNativeEngine::NotifyForceExpandState([[maybe_unused]] int32_t value)
1676 {
1677     HILOG_WARN("ARK does not support dfx on windows");
1678 }
1679 #endif
1680 
SetMockModuleList(const std::map<std::string,std::string> & list)1681 void ArkNativeEngine::SetMockModuleList(const std::map<std::string, std::string> &list)
1682 {
1683     JSNApi::SetMockModuleList(vm_, list);
1684 }
1685 
RegisterNapiUncaughtExceptionHandler(NapiUncaughtExceptionCallback callback)1686 void ArkNativeEngine::RegisterNapiUncaughtExceptionHandler(NapiUncaughtExceptionCallback callback)
1687 {
1688     JSNApi::EnableUserUncaughtErrorHandler(vm_);
1689     napiUncaughtExceptionCallback_ = callback;
1690 }
1691 
HandleUncaughtException()1692 void ArkNativeEngine::HandleUncaughtException()
1693 {
1694     if (napiUncaughtExceptionCallback_ == nullptr) {
1695         return;
1696     }
1697     LocalScope scope(vm_);
1698     lastException_.Empty();
1699     Local<ObjectRef> exception = JSNApi::GetAndClearUncaughtException(vm_);
1700     if (!exception.IsEmpty() && !exception->IsHole()) {
1701         if (napiUncaughtExceptionCallback_ != nullptr) {
1702             napiUncaughtExceptionCallback_(ArkValueToNapiValue(reinterpret_cast<napi_env>(this), exception));
1703         }
1704     }
1705 }
1706 
HasPendingException()1707 bool ArkNativeEngine::HasPendingException()
1708 {
1709     return panda::JSNApi::HasPendingException(vm_);
1710 }
1711 
RegisterPermissionCheck(PermissionCheckCallback callback)1712 void ArkNativeEngine::RegisterPermissionCheck(PermissionCheckCallback callback)
1713 {
1714     if (permissionCheckCallback_ == nullptr) {
1715         permissionCheckCallback_ = callback;
1716     }
1717 }
1718 
ExecutePermissionCheck()1719 bool ArkNativeEngine::ExecutePermissionCheck()
1720 {
1721     if (permissionCheckCallback_ != nullptr) {
1722         return permissionCheckCallback_();
1723     } else {
1724         HILOG_INFO("permissionCheckCallback_ is still nullptr when executing permission check!");
1725         return true;
1726     }
1727 }
1728 
RegisterTranslateBySourceMap(SourceMapCallback callback)1729 void ArkNativeEngine::RegisterTranslateBySourceMap(SourceMapCallback callback)
1730 {
1731     if (SourceMapCallback_ == nullptr) {
1732         SourceMapCallback_ = callback;
1733     }
1734     // regedit SourceMapCallback to ark_js_runtime
1735     panda::JSNApi::SetSourceMapCallback(vm_, callback);
1736 }
1737 
RegisterSourceMapTranslateCallback(SourceMapTranslateCallback callback)1738 void ArkNativeEngine::RegisterSourceMapTranslateCallback(SourceMapTranslateCallback callback)
1739 {
1740     panda::JSNApi::SetSourceMapTranslateCallback(vm_, callback);
1741 }
1742 
ExecuteTranslateBySourceMap(const std::string & rawStack)1743 std::string ArkNativeEngine::ExecuteTranslateBySourceMap(const std::string& rawStack)
1744 {
1745     if (SourceMapCallback_ != nullptr) {
1746         return SourceMapCallback_(rawStack);
1747     } else {
1748         HILOG_WARN("SourceMapCallback_ is nullptr.");
1749         return "";
1750     }
1751 }
1752 
IsMixedDebugEnabled()1753 bool ArkNativeEngine::IsMixedDebugEnabled()
1754 {
1755     return JSNApi::IsMixedDebugEnabled(vm_);
1756 }
1757 
NotifyNativeCalling(const void * nativeAddress)1758 void ArkNativeEngine::NotifyNativeCalling(const void *nativeAddress)
1759 {
1760     JSNApi::NotifyNativeCalling(vm_, nativeAddress);
1761 }
1762 
AllowCrossThreadExecution() const1763 void ArkNativeEngine::AllowCrossThreadExecution() const
1764 {
1765     JSNApi::AllowCrossThreadExecution(vm_);
1766 }
1767 
1768 #if !defined(PREVIEW) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
GetCurrentTickMillseconds()1769 uint64_t ArkNativeEngine::GetCurrentTickMillseconds()
1770 {
1771     return std::chrono::duration_cast<std::chrono::milliseconds>(
1772         std::chrono::steady_clock::now().time_since_epoch()).count();
1773 }
1774 
AsyncAfterWorkCallback(uv_work_t * req,int status)1775 void AsyncAfterWorkCallback(uv_work_t* req, int status)
1776 {
1777     if (req == nullptr) {
1778         HILOG_ERROR("dumpheapSnapshot AsyncAfterWorkCallback req is nullptr");
1779         return;
1780     }
1781     if (status) {
1782         HILOG_ERROR("dumpheapSnapshot AsyncAfterWorkCallback failed");
1783     }
1784     auto work = reinterpret_cast<JsHeapDumpWork*>(req->data);
1785     if (work == nullptr) {
1786         HILOG_ERROR("dumpheapSnapshot JsHeapDumpWork is nullptr");
1787         return;
1788     }
1789     size_t heapUsedSize = DFXJSNApi::GetHeapUsedSize(work->vm);
1790     size_t nowPrecent = heapUsedSize * DEC_TO_INT / (work->limitSize);
1791     HILOG_INFO("dumpheapSnapshot nowPrecent is %{public}zu", nowPrecent);
1792     if (nowPrecent >= g_threshold) {
1793         auto vm = work->vm;
1794         DFXJSNApi::GetHeapPrepare(vm);
1795         DFXJSNApi::SetOverLimit(vm, true);
1796         HILOG_INFO("dumpheapSnapshot GetHeapPrepare done");
1797     }
1798     work->condition->notify_all();
1799     delete work;
1800 }
1801 
JudgmentDump(size_t limitSize)1802 void ArkNativeEngine::JudgmentDump(size_t limitSize)
1803 {
1804     if (!limitSize) {
1805         return;
1806     }
1807     size_t nowPrecent = GetHeapObjectSize() * DEC_TO_INT / limitSize;
1808     if (g_debugLeak || (nowPrecent >= g_threshold && (g_lastHeapDumpTime == 0 ||
1809         GetCurrentTickMillseconds() - g_lastHeapDumpTime > HEAP_DUMP_REPORT_INTERVAL))) {
1810         int pid = -1;
1811         std::unique_lock<std::mutex> lock(lock_);
1812         dumpWork_ = new(std::nothrow) JsHeapDumpWork;
1813         dumpWork_->vm = vm_;
1814         dumpWork_->work.data = dumpWork_;
1815         dumpWork_->condition = &condition_;
1816         dumpWork_->limitSize = limitSize;
1817         uv_loop_t *loop = GetUVLoop();
1818         uv_queue_work(loop, &(dumpWork_->work), [](uv_work_t *) {}, AsyncAfterWorkCallback);
1819         condition_.wait(lock);
1820         // VM destructed but syncTask is executed.
1821         if (needStop_ || !DFXJSNApi::isOverLimit(vm_)) {
1822             return;
1823         }
1824         DFXJSNApi::SetOverLimit(vm_, false);
1825         HILOG_INFO("dumpheapSnapshot ready");
1826         time_t startTime = time(nullptr);
1827         g_lastHeapDumpTime = GetCurrentTickMillseconds();
1828         if((pid = fork()) < 0) {
1829             HILOG_ERROR("ready dumpheapSnapshot Fork error, err:%{public}d", errno);
1830             sleep(g_checkInterval);
1831             return;
1832         }
1833         if (pid == 0) {
1834             AllowCrossThreadExecution();
1835             DumpHeapSnapshot(true, DumpFormat::JSON, false, false);
1836             HILOG_INFO("dumpheapSnapshot successful, now you can check some file");
1837             _exit(0);
1838         }
1839         while (true) {
1840             int status = 0;
1841             pid_t p = waitpid(pid, &status, 0);
1842             if (p < 0) {
1843                 HILOG_ERROR("dumpheapSnapshot Waitpid return p=%{public}d, err:%{public}d", p, errno);
1844                 break;
1845             }
1846             if (p == pid) {
1847                 HILOG_ERROR("dumpheapSnapshot dump process exited status is %{public}d", status);
1848                 break;
1849             }
1850             if (time(nullptr) > startTime + TIME_OUT) {
1851                 HILOG_ERROR("time out to wait child process, killing forkpid %{public}d", pid);
1852                 kill(pid, SIGKILL);
1853                 break;
1854             }
1855             usleep(DEFAULT_SLEEP_TIME);
1856         }
1857     }
1858 }
1859 
JsHeapStart()1860 void ArkNativeEngine::JsHeapStart()
1861 {
1862     if (pthread_setname_np(pthread_self(), "OS_JsHeapThread") != 0) {
1863         HILOG_ERROR("Failed to set threadName for JsHeap, errno:%d", errno);
1864     }
1865     while (!needStop_) {
1866         {
1867             std::unique_lock<std::mutex> lock(lock_);
1868             condition_.wait_for(lock, std::chrono::milliseconds(g_checkInterval * SEC_TO_MILSEC));
1869             if (needStop_) {
1870                 return;
1871             }
1872         }
1873         size_t limitSize = GetHeapLimitSize();
1874         JudgmentDump(limitSize);
1875     }
1876 }
1877 #endif
1878 
StartMonitorJSHeapUsage()1879 void ArkNativeEngine::StartMonitorJSHeapUsage()
1880 {
1881 #if !defined(PREVIEW) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
1882     if (!g_enableProperty) {
1883         return;
1884     }
1885     if (threadJsHeap_ == nullptr && !IsInAppspawn()) {
1886         threadJsHeap_ = std::make_unique<std::thread>(&ArkNativeEngine::JsHeapStart, this);
1887         HILOG_DEBUG("JsHeapStart is OK");
1888     }
1889 #else
1890     HILOG_ERROR("StartMonitorJSHeapUsage does not support dfx");
1891 #endif
1892 }
1893 
StopMonitorJSHeapUsage()1894 void ArkNativeEngine::StopMonitorJSHeapUsage()
1895 {
1896 #if !defined(PREVIEW) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
1897     if (threadJsHeap_ != nullptr) {
1898         // Free threadJsHeap_
1899         needStop_ = true;
1900         condition_.notify_all();
1901         if (threadJsHeap_->joinable()) {
1902             threadJsHeap_->join();
1903             threadJsHeap_ = nullptr;
1904         }
1905     }
1906 #else
1907     HILOG_ERROR("StopMonitorJSHeapUsage does not support dfx");
1908 #endif
1909 }
1910