• 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 #ifndef FOUNDATION_ACE_NAPI_NATIVE_ENGINE_NATIVE_ENGINE_H
17 #define FOUNDATION_ACE_NAPI_NATIVE_ENGINE_NATIVE_ENGINE_H
18 
19 #include <functional>
20 #include <list>
21 #include <string>
22 #include <unordered_map>
23 #include <unordered_set>
24 #include <vector>
25 #ifdef LINUX_PLATFORM
26 #include<atomic>
27 #endif
28 
29 #include "callback_scope_manager/native_callback_scope_manager.h"
30 #include "ecmascript/napi/include/jsnapi.h"
31 #include "module_manager/native_module_manager.h"
32 #include "native_engine/native_async_work.h"
33 #include "native_engine/native_deferred.h"
34 #include "native_engine/native_reference.h"
35 #include "native_engine/native_safe_async_work.h"
36 #include "native_engine/native_value.h"
37 #include "native_property.h"
38 #include "reference_manager/native_reference_manager.h"
39 #include "utils/macros.h"
40 
41 namespace panda::ecmascript {
42     class EcmaVM;
43 }
44 
45 typedef int32_t (*GetContainerScopeIdCallback)(void);
46 typedef void (*ContainerScopeCallback)(int32_t);
47 typedef struct uv_loop_s uv_loop_t;
48 
49 struct NativeErrorExtendedInfo {
50     const char* message = nullptr;
51     void* reserved = nullptr;
52     uint32_t engineErrorCode = 0;
53     int errorCode = 0;
54 };
55 
56 struct ExceptionInfo {
57     const char* message_ = nullptr;
58     int32_t lineno_ = 0;
59     int32_t colno_ = 0;
60 
~ExceptionInfoExceptionInfo61     ~ExceptionInfo()
62     {
63         if (message_ != nullptr) {
64             delete[] message_;
65         }
66     }
67 };
68 
69 enum LoopMode {
70     LOOP_DEFAULT, LOOP_ONCE, LOOP_NOWAIT
71 };
72 
73 enum class DumpFormat {
74     JSON, BINARY, OTHER
75 };
76 
77 enum class WorkerVersion {
78     NONE, OLD, NEW
79 };
80 
81 class CleanupHookCallback {
82 public:
83     using Callback = void (*)(void*);
84 
CleanupHookCallback(Callback fn,void * arg,uint64_t insertion_order_counter)85     CleanupHookCallback(Callback fn, void* arg, uint64_t insertion_order_counter)
86         : fn_(fn), arg_(arg), insertion_order_counter_(insertion_order_counter)
87     {}
88 
89     struct Hash {
operatorHash90         inline size_t operator()(const CleanupHookCallback& cb) const
91         {
92             return std::hash<void*>()(cb.arg_);
93         }
94     };
95     struct Equal {
operatorEqual96         inline bool operator()(const CleanupHookCallback& a, const CleanupHookCallback& b) const
97         {
98             return a.fn_ == b.fn_ && a.arg_ == b.arg_;
99         };
100     };
101 
102 private:
103     friend class NativeEngine;
104     Callback fn_;
105     void* arg_;
106     uint64_t insertion_order_counter_;
107 };
108 
109 using PostTask = std::function<void(bool needSync)>;
110 using CleanEnv = std::function<void()>;
111 using InitWorkerFunc = std::function<void(NativeEngine* engine)>;
112 using GetAssetFunc = std::function<void(const std::string& uri, std::vector<uint8_t>& content, std::string& ami)>;
113 using OffWorkerFunc = std::function<void(NativeEngine* engine)>;
114 using DebuggerPostTask = std::function<void(std::function<void()>&&)>;
115 using NapiUncaughtExceptionCallback = std::function<void(napi_value value)>;
116 using PermissionCheckCallback = std::function<bool()>;
117 using NapiConcurrentCallback = void (*)(napi_env env, napi_value result, bool success, void* data);
118 using SourceMapCallback = std::function<std::string(const std::string& rawStack)>;
119 using SourceMapTranslateCallback = std::function<bool(std::string& url, int& line, int& column)>;
120 using EcmaVM = panda::ecmascript::EcmaVM;
121 
122 class NAPI_EXPORT NativeEngine {
123 public:
124     explicit NativeEngine(void* jsEngine);
125     virtual ~NativeEngine();
126 
127     virtual NativeModuleManager* GetModuleManager();
128     virtual NativeReferenceManager* GetReferenceManager();
129     virtual NativeCallbackScopeManager* GetCallbackScopeManager();
130     virtual uv_loop_t* GetUVLoop() const;
131     virtual pthread_t GetTid() const;
132 
133     virtual bool ReinitUVLoop();
134 
135     virtual void Loop(LoopMode mode, bool needSync = false);
136     virtual void SetPostTask(PostTask postTask);
137     virtual void TriggerPostTask();
138 #if !defined(PREVIEW)
139     virtual void CheckUVLoop();
140     virtual void CancelCheckUVLoop();
141 #endif
142     virtual void* GetJsEngine();
143 
144     virtual const EcmaVM* GetEcmaVm() const = 0;
145     virtual void SetPromiseRejectCallback(NativeReference* rejectCallbackRef, NativeReference* checkCallbackRef) = 0;
146 
147     virtual bool InitTaskPoolThread(NativeEngine* engine, NapiConcurrentCallback callback) = 0;
148     virtual bool InitTaskPoolThread(napi_env env, NapiConcurrentCallback callback) = 0;
149     virtual bool InitTaskPoolFunc(napi_env env, napi_value func, void* taskInfo) = 0;
150     virtual bool HasPendingJob() const = 0;
151     virtual bool IsProfiling() const = 0;
152     virtual bool IsExecutingPendingJob() const = 0;
153     virtual void* GetCurrentTaskInfo() const = 0;
154     virtual void TerminateExecution() const = 0;
155 
156     virtual napi_value CallFunction(napi_value thisVar,
157                                     napi_value function,
158                                     napi_value const *argv,
159                                     size_t argc) = 0;
160     virtual bool RunScriptPath(const char* path) = 0;
161     virtual napi_value RunScriptBuffer(const char* path, std::vector<uint8_t>& buffer, bool isBundle) = 0;
162     virtual bool RunScriptBuffer(const std::string &path, uint8_t* buffer, size_t size, bool isBundle) = 0;
163     virtual napi_value RunBufferScript(std::vector<uint8_t>& buffer) = 0;
164     virtual napi_value RunActor(std::vector<uint8_t>& buffer, const char* descriptor, char* entryPoint = nullptr) = 0;
165 
166     virtual napi_value CreateInstance(napi_value constructor, napi_value const *argv, size_t argc) = 0;
167 
168     virtual NativeReference* CreateReference(napi_value value, uint32_t initialRefcount,
169         bool flag = false, NapiNativeFinalize callback = nullptr, void* data = nullptr, void* hint = nullptr) = 0;
170 
171     virtual NativeAsyncWork* CreateAsyncWork(napi_value asyncResource,
172                                              napi_value asyncResourceName,
173                                              NativeAsyncExecuteCallback execute,
174                                              NativeAsyncCompleteCallback complete,
175                                              void* data);
176 
177     virtual NativeAsyncWork* CreateAsyncWork(const std::string &asyncResourceName,
178                                              NativeAsyncExecuteCallback execute,
179                                              NativeAsyncCompleteCallback complete,
180                                              void* data);
181     virtual NativeSafeAsyncWork* CreateSafeAsyncWork(napi_value func, napi_value asyncResource,
182         napi_value asyncResourceName, size_t maxQueueSize, size_t threadCount, void* finalizeData,
183         NativeFinalize finalizeCallback, void* context, NativeThreadSafeFunctionCallJs callJsCallback);
184 
185     virtual void* CreateRuntime(bool isLimitedWorker = false) = 0;
186     virtual napi_value CreatePromise(NativeDeferred** deferred) = 0;
187 
188     virtual void StartCpuProfiler(const std::string& fileName = "") = 0;
189     virtual void StopCpuProfiler() = 0;
190 
191     virtual void ResumeVM() = 0;
192     virtual bool SuspendVM() = 0;
193     virtual bool IsSuspended() = 0;
194     virtual bool CheckSafepoint() = 0;
195     virtual bool SuspendVMById(uint32_t tid) = 0;
196     virtual void ResumeVMById(uint32_t tid) = 0;
197 
198     virtual void DumpHeapSnapshot(const std::string &path, bool isVmMode = true,
199         DumpFormat dumpFormat = DumpFormat::JSON) = 0;
200     virtual void DumpCpuProfile(bool isVmMode = true, DumpFormat dumpFormat = DumpFormat::JSON,
201         bool isPrivate = false, bool isFullGC = true) = 0;
202     virtual void DumpHeapSnapshot(bool isVmMode = true, DumpFormat dumpFormat = DumpFormat::JSON,
203         bool isPrivate = false, bool isFullGC = true) = 0;
204     virtual bool BuildNativeAndJsStackTrace(std::string &stackTraceStr) = 0;
205     virtual bool BuildJsStackTrace(std::string &stackTraceStr) = 0;
206     virtual bool BuildJsStackInfoList(uint32_t tid, std::vector<JsFrameInfo>& jsFrames) = 0;
207     virtual bool DeleteWorker(NativeEngine* workerEngine) = 0;
208     virtual bool StartHeapTracking(double timeInterval, bool isVmMode = true) = 0;
209     virtual bool StopHeapTracking(const std::string &filePath) = 0;
210 
211     virtual void AllowCrossThreadExecution() const = 0;
212 
213     NativeErrorExtendedInfo* GetLastError();
214     void SetLastError(int errorCode, uint32_t engineErrorCode = 0, void* engineReserved = nullptr);
ClearLastError()215     void ClearLastError()
216     {
217         lastError_.errorCode = 0;
218         lastError_.engineErrorCode = 0;
219         lastError_.message = nullptr;
220         lastError_.reserved = nullptr;
221     }
222     void EncodeToUtf8(napi_value value, char* buffer, int32_t* written, size_t bufferSize, int32_t* nchars);
223     void EncodeToChinese(napi_value value, std::string& buffer, const std::string& encoding);
224     NativeEngine(NativeEngine&) = delete;
225     virtual NativeEngine& operator=(NativeEngine&) = delete;
226 
227     virtual napi_value ValueToNapiValue(JSValueWrapper& value) = 0;
228     virtual std::string GetSourceCodeInfo(napi_value value, ErrorPos pos) = 0;
229 
230     virtual bool TriggerFatalException(napi_value error) = 0;
231     virtual bool AdjustExternalMemory(int64_t ChangeInBytes, int64_t* AdjustedValue) = 0;
232 
MarkWorkerThread()233     void MarkWorkerThread()
234     {
235         jsThreadType_ = JSThreadType::WORKER_THREAD;
236     }
MarkRestrictedWorkerThread()237     void MarkRestrictedWorkerThread()
238     {
239         jsThreadType_ = JSThreadType::RESTRICTEDWORKER_THREAD;
240     }
MarkTaskPoolThread()241     void MarkTaskPoolThread()
242     {
243         jsThreadType_ = JSThreadType::TASKPOOL_THREAD;
244     }
IsWorkerThread()245     bool IsWorkerThread() const
246     {
247         return jsThreadType_ == JSThreadType::WORKER_THREAD;
248     }
IsRestrictedWorkerThread()249     bool IsRestrictedWorkerThread() const
250     {
251         return jsThreadType_ == JSThreadType::RESTRICTEDWORKER_THREAD;
252     }
IsTaskPoolThread()253     bool IsTaskPoolThread() const
254     {
255         return jsThreadType_ == JSThreadType::TASKPOOL_THREAD;
256     }
IsMainThread()257     bool IsMainThread() const
258     {
259         return jsThreadType_ == JSThreadType::MAIN_THREAD;
260     }
261 
CheckAndSetWorkerVersion(WorkerVersion expected,WorkerVersion desired)262     bool CheckAndSetWorkerVersion(WorkerVersion expected, WorkerVersion desired)
263     {
264         return workerVersion_.compare_exchange_strong(expected, desired);
265     }
IsTargetWorkerVersion(WorkerVersion target)266     bool IsTargetWorkerVersion(WorkerVersion target) const
267     {
268         return workerVersion_.load() == target;
269     }
270 
IncreaseSubEnvCounter()271     void IncreaseSubEnvCounter()
272     {
273         subEnvCounter_++;
274     }
DecreaseSubEnvCounter()275     void DecreaseSubEnvCounter()
276     {
277         subEnvCounter_--;
278     }
HasSubEnv()279     bool HasSubEnv()
280     {
281         return subEnvCounter_.load() != 0;
282     }
283 
SetCleanEnv(CleanEnv cleanEnv)284     void SetCleanEnv(CleanEnv cleanEnv)
285     {
286         cleanEnv_ = cleanEnv;
287     }
288 
289     // register init worker func
290     virtual void SetInitWorkerFunc(InitWorkerFunc func);
291     InitWorkerFunc GetInitWorkerFunc() const;
292     virtual void SetGetAssetFunc(GetAssetFunc func);
293     GetAssetFunc GetGetAssetFunc() const;
294     virtual void SetOffWorkerFunc(OffWorkerFunc func);
295     OffWorkerFunc GetOffWorkerFunc() const;
296 
297     // call init worker func
298     virtual bool CallInitWorkerFunc(NativeEngine* engine);
299     virtual bool CallGetAssetFunc(const std::string& uri, std::vector<uint8_t>& content, std::string& ami);
300     virtual bool CallOffWorkerFunc(NativeEngine* engine);
301 
302     // adapt worker to ace container
303     virtual void SetGetContainerScopeIdFunc(GetContainerScopeIdCallback func);
304     virtual void SetInitContainerScopeFunc(ContainerScopeCallback func);
305     virtual void SetFinishContainerScopeFunc(ContainerScopeCallback func);
306     virtual int32_t GetContainerScopeIdFunc();
307     virtual bool InitContainerScopeFunc(int32_t id);
308     virtual bool FinishContainerScopeFunc(int32_t id);
309 
310 #if !defined(PREVIEW)
311     virtual void SetDebuggerPostTaskFunc(DebuggerPostTask func);
312     virtual void CallDebuggerPostTaskFunc(std::function<void()>&& task);
313 #endif
314 
315     virtual void StartMonitorJSHeapUsage() = 0;
316     virtual void StopMonitorJSHeapUsage() = 0;
317 
318     virtual void SetHostEngine(NativeEngine* engine);
319     virtual NativeEngine* GetHostEngine() const;
320 
321     using CleanupCallback = CleanupHookCallback::Callback;
322     virtual void AddCleanupHook(CleanupCallback fun, void* arg);
323     virtual void RemoveCleanupHook(CleanupCallback fun, void* arg);
324 
325     void CleanupHandles();
326     void IncreaseWaitingRequestCounter();
327     void DecreaseWaitingRequestCounter();
328     bool HasWaitingRequest();
329 
330     void IncreaseListeningCounter();
331     void DecreaseListeningCounter();
332     bool HasListeningCounter();
333 
334     virtual void RunCleanup();
335 
IsStopping()336     bool IsStopping() const
337     {
338         return isStopping_.load();
339     }
340 
SetStopping(bool value)341     void SetStopping(bool value)
342     {
343         isStopping_.store(value);
344     }
345 
346     virtual void PrintStatisticResult() = 0;
347     virtual void StartRuntimeStat() = 0;
348     virtual void StopRuntimeStat() = 0;
349     virtual size_t GetArrayBufferSize() = 0;
350     virtual size_t GetHeapTotalSize() = 0;
351     virtual size_t GetHeapUsedSize() = 0;
352     virtual size_t GetHeapObjectSize() = 0;
353     virtual size_t GetHeapLimitSize() = 0;
354     virtual void NotifyApplicationState(bool inBackground) = 0;
355     virtual void NotifyIdleStatusControl(std::function<void(bool)> callback) = 0;
356     virtual void NotifyIdleTime(int idleMicroSec) = 0;
357     virtual void NotifyMemoryPressure(bool inHighMemoryPressure = false) = 0;
358     virtual void NotifyForceExpandState(int32_t value) = 0;
359     virtual void SetMockModuleList(const std::map<std::string, std::string> &list) = 0;
360 
361     void RegisterWorkerFunction(const NativeEngine* engine);
362     virtual void RegisterNapiUncaughtExceptionHandler(NapiUncaughtExceptionCallback callback) = 0;
363     virtual void HandleUncaughtException() = 0;
HasPendingException()364     virtual bool HasPendingException()
365     {
366         return false;
367     }
368     virtual void RegisterPermissionCheck(PermissionCheckCallback callback) = 0;
369     virtual bool ExecutePermissionCheck() = 0;
370     virtual void RegisterTranslateBySourceMap(SourceMapCallback callback) = 0;
371     virtual std::string ExecuteTranslateBySourceMap(const std::string& rawStack) = 0;
372     virtual void RegisterSourceMapTranslateCallback(SourceMapTranslateCallback callback) = 0;
373     virtual void SetPromiseRejectCallBackRef(NativeReference*) = 0;
374     virtual void SetCheckCallbackRef(NativeReference*) = 0;
375     virtual NapiUncaughtExceptionCallback GetNapiUncaughtExceptionCallback() = 0;
376     virtual void* GetPromiseRejectCallback() = 0;
377     virtual void GetCurrentModuleInfo(std::string& moduleName, std::string& fileName, bool needRecordName) = 0;
378     virtual bool GetIsBundle() = 0;
379     // run script by path
380     napi_value RunScriptForAbc(const char* path, char* entryPoint = nullptr);
381     napi_value RunScript(const char* path, char* entryPoint = nullptr);
382 
383     const char* GetModuleFileName();
384 
385     void SetModuleName(std::string &moduleName);
386     void SetModuleFileName(std::string &moduleFileName);
387 
388     void SetInstanceData(void* data, NativeFinalize finalize_cb, void* hint);
389     void GetInstanceData(void** data);
390 
391     /**
392      * @brief Set the Extension Infos
393      *
394      * @param extensionInfos extension infos to set
395      */
396     void SetExtensionInfos(std::unordered_map<std::string, int32_t>&& extensionInfos);
397 
398     /**
399      * @brief Get the Extension Infos
400      *
401      * @return extension infos
402      */
403     const std::unordered_map<std::string, int32_t>& GetExtensionInfos();
404 
405     /**
406      * @brief Set the Module Blocklist
407      *
408      * @param blocklist the blocklist set to native engine
409      */
410     void SetModuleBlocklist(std::unordered_map<int32_t, std::unordered_set<std::string>>&& blocklist);
411 
412     /**
413      * @brief Set the Module Load Checker
414      *
415      * @param moduleCheckerDelegate the module checker delegate will intercept the module loading
416      */
417     void SetModuleLoadChecker(const std::shared_ptr<ModuleCheckerDelegate>& moduleCheckerDelegate);
418 
419     virtual napi_value NapiLoadModule(const char* str) = 0;
420 
NewAsyncId()421     double NewAsyncId()
422     {
423         return 0;
424     }
425 
GetDefaultTriggerAsyncId()426     double GetDefaultTriggerAsyncId()
427     {
428         return 0;
429     }
430 
431 private:
432     void StartCleanupTimer();
433 protected:
434     void *jsEngine_;
435     void* jsEngineInterface_;
436 
437     void Init();
438     void Deinit();
439 
440     NativeModuleManager* moduleManager_ = nullptr;
441     NativeReferenceManager* referenceManager_ = nullptr;
442     NativeCallbackScopeManager* callbackScopeManager_ = nullptr;
443 
444     uv_loop_t* loop_ = nullptr;
445 
446     NativeErrorExtendedInfo lastError_;
447 
448     // register for worker
449     InitWorkerFunc initWorkerFunc_ {nullptr};
450     GetAssetFunc getAssetFunc_ {nullptr};
451     OffWorkerFunc offWorkerFunc_ {nullptr};
452 #if !defined(PREVIEW)
453     DebuggerPostTask debuggerPostTaskFunc_ {nullptr};
454 #endif
455     NativeEngine* hostEngine_ {nullptr};
456     bool isAppModule_ = false;
457 
458 public:
459     uint64_t openHandleScopes_ = 0;
460     panda::Local<panda::ObjectRef> lastException_;
461 
462 private:
463     std::string moduleName_;
464     std::string moduleFileName_;
465     std::mutex instanceDataLock_;
466     NativeObjectInfo instanceDataInfo_;
467     void FinalizerInstanceData(void);
468     pthread_t tid_ = 0;
469     std::unordered_map<std::string, int32_t> extensionInfos_;
470     uv_sem_t uvSem_;
471 
472     // the old worker api use before api9, the new worker api start with api9
473     enum JSThreadType { MAIN_THREAD, WORKER_THREAD, TASKPOOL_THREAD, RESTRICTEDWORKER_THREAD};
474     JSThreadType jsThreadType_ = JSThreadType::MAIN_THREAD;
475     // current is hostengine, can create old worker, new worker, or no workers on hostengine
476     std::atomic<WorkerVersion> workerVersion_ { WorkerVersion::NONE };
477 
478 #if !defined(PREVIEW)
479     static void UVThreadRunner(void* nativeEngine);
480     void PostLoopTask();
481 
482     bool checkUVLoop_ = false;
483     uv_thread_t uvThread_;
484 #endif
485 
486     PostTask postTask_ = nullptr;
487     CleanEnv cleanEnv_ = nullptr;
488     uv_async_t uvAsync_;
489     std::unordered_set<CleanupHookCallback, CleanupHookCallback::Hash, CleanupHookCallback::Equal> cleanup_hooks_;
490     uint64_t cleanup_hook_counter_ = 0;
491     std::atomic_int requestWaiting_ { 0 };
492     std::atomic_int listeningCounter_ { 0 };
493     std::atomic_int subEnvCounter_ { 0 };
494     std::atomic_bool isStopping_ { false };
495     bool cleanupTimeout_ = false;
496     uv_timer_t timer_;
497 };
498 
499 class TryCatch : public panda::TryCatch {
500 public:
TryCatch(napi_env env)501     explicit TryCatch(napi_env env)
502         : panda::TryCatch(reinterpret_cast<NativeEngine*>(env)->GetEcmaVm()),
503           engine_(reinterpret_cast<NativeEngine*>(env)) {}
504 
~TryCatch()505     ~TryCatch()
506     {
507         if (HasCaught()) {
508             engine_->lastException_ = GetException();
509         }
510     }
511 private:
512    NativeEngine* engine_ = nullptr;
513 };
514 #endif /* FOUNDATION_ACE_NAPI_NATIVE_ENGINE_NATIVE_ENGINE_H */
515