• 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 ECMASCRIPT_ECMA_VM_H
17 #define ECMASCRIPT_ECMA_VM_H
18 
19 #include <mutex>
20 
21 #include "ecmascript/base/config.h"
22 #include "ecmascript/builtins/builtins_method_index.h"
23 #include "ecmascript/ecma_context.h"
24 #include "ecmascript/js_runtime_options.h"
25 #include "ecmascript/js_thread.h"
26 #include "ecmascript/mem/c_containers.h"
27 #include "ecmascript/mem/c_string.h"
28 #include "ecmascript/mem/gc_stats.h"
29 #include "ecmascript/napi/include/dfx_jsnapi.h"
30 #include "ecmascript/napi/include/jsnapi.h"
31 #include "ecmascript/pgo_profiler/pgo_profiler.h"
32 #include "ecmascript/taskpool/taskpool.h"
33 
34 namespace panda {
35 class JSNApi;
36 struct HmsMap;
37 namespace panda_file {
38 class File;
39 }  // namespace panda_file
40 
41 namespace ecmascript {
42 class GlobalEnv;
43 class ObjectFactory;
44 class RegExpParserCache;
45 class EcmaRuntimeStat;
46 class Heap;
47 class HeapTracker;
48 class JSNativePointer;
49 class Program;
50 class GCStats;
51 class CpuProfiler;
52 class Tracing;
53 class RegExpExecResultCache;
54 class JSPromise;
55 enum class PromiseRejectionEvent : uint8_t;
56 class JSPandaFileManager;
57 class JSPandaFile;
58 class EcmaStringTable;
59 class SnapshotEnv;
60 class SnapshotSerialize;
61 class SnapshotProcessor;
62 using PGOProfiler = pgo::PGOProfiler;
63 #if !WIN_OR_MAC_OR_IOS_PLATFORM
64 class HeapProfilerInterface;
65 class HeapProfiler;
66 #endif
67 namespace job {
68 class MicroJobQueue;
69 }  // namespace job
70 
71 namespace tooling {
72 class JsDebuggerManager;
73 }  // namespace tooling
74 
75 template<typename T>
76 class JSHandle;
77 class JSArrayBuffer;
78 class JSFunction;
79 class SourceTextModule;
80 class Program;
81 class TSManager;
82 class AOTFileManager;
83 class SlowRuntimeStub;
84 class RequireManager;
85 class QuickFixManager;
86 class ConstantPool;
87 class FunctionCallTimer;
88 class EcmaStringTable;
89 class JSObjectResizingStrategy;
90 class Jit;
91 
92 using NativePtrGetter = void* (*)(void* info);
93 using SourceMapCallback = std::function<std::string(const std::string& rawStack)>;
94 using SourceMapTranslateCallback = std::function<bool(std::string& url, int& line, int& column)>;
95 using ResolveBufferCallback = std::function<bool(std::string dirPath, uint8_t **buff, size_t *buffSize)>;
96 using UnloadNativeModuleCallback = std::function<bool(const std::string &moduleKey)>;
97 using RequestAotCallback =
98     std::function<int32_t(const std::string &bundleName, const std::string &moduleName, int32_t triggerMode)>;
99 using SearchHapPathCallBack = std::function<bool(const std::string moduleName, std::string &hapPath)>;
100 using DeviceDisconnectCallback = std::function<bool()>;
101 using UncatchableErrorHandler = std::function<void(panda::TryCatch&)>;
102 class EcmaVM {
103 public:
104     static EcmaVM *Create(const JSRuntimeOptions &options, EcmaParamConfiguration &config);
105 
106     static bool Destroy(EcmaVM *vm);
107 
108     EcmaVM(JSRuntimeOptions options, EcmaParamConfiguration config);
109 
110     EcmaVM();
111 
112     ~EcmaVM();
113 
SetLoop(void * loop)114     void SetLoop(void *loop)
115     {
116         loop_ = loop;
117     }
118 
GetLoop()119     void *GetLoop() const
120     {
121         return loop_;
122     }
123 
IsInitialized()124     bool IsInitialized() const
125     {
126         return initialized_;
127     }
128 
GetFactory()129     ObjectFactory *GetFactory() const
130     {
131         return factory_;
132     }
133 
134     void InitializePGOProfiler();
135     void ResetPGOProfiler();
136 
137     bool IsEnablePGOProfiler() const;
138     bool IsEnableElementsKind() const;
139 
140     bool Initialize();
141 
GetEcmaGCStats()142     GCStats *GetEcmaGCStats() const
143     {
144         return gcStats_;
145     }
146 
GetAssociatedJSThread()147     JSThread *GetAssociatedJSThread() const
148     {
149         return thread_;
150     }
151 
GetJSOptions()152     JSRuntimeOptions &GetJSOptions()
153     {
154         return options_;
155     }
156 
GetEcmaParamConfiguration()157     const EcmaParamConfiguration &GetEcmaParamConfiguration() const
158     {
159         return ecmaParamConfiguration_;
160     }
161 
162     JSHandle<GlobalEnv> GetGlobalEnv() const;
163 
ConstCast(const EcmaVM * vm)164     static EcmaVM *ConstCast(const EcmaVM *vm)
165     {
166         return const_cast<EcmaVM *>(vm);
167     }
168 
CheckThread()169     void CheckThread() const
170     {
171         // Exclude GC thread
172         if (thread_ == nullptr) {
173             LOG_FULL(FATAL) << "Fatal: ecma_vm has been destructed! vm address is: " << this;
174         }
175         if (!Taskpool::GetCurrentTaskpool()->IsInThreadPool(std::this_thread::get_id()) &&
176             thread_->GetThreadId() != JSThread::GetCurrentThreadId() && !thread_->IsCrossThreadExecutionEnable()) {
177                 LOG_FULL(FATAL) << "Fatal: ecma_vm cannot run in multi-thread!"
178                                     << " thread:" << thread_->GetThreadId()
179                                     << " currentThread:" << JSThread::GetCurrentThreadId();
180         }
181     }
182 
GetAndFastCheckJSThread()183     JSThread *GetAndFastCheckJSThread() const
184     {
185         if (thread_ == nullptr) {
186             LOG_FULL(FATAL) << "Fatal: ecma_vm has been destructed! vm address is: " << this;
187         }
188         if (thread_->GetThreadId() != JSThread::GetCurrentThreadId() && !thread_->IsCrossThreadExecutionEnable()) {
189             LOG_FULL(FATAL) << "Fatal: ecma_vm cannot run in multi-thread!"
190                                     << " thread:" << thread_->GetThreadId()
191                                     << " currentThread:" << JSThread::GetCurrentThreadId();
192         }
193         return thread_;
194     }
195 
GetJSThread()196     ARK_INLINE JSThread *GetJSThread() const
197     {
198         if (options_.EnableThreadCheck()) {
199             CheckThread();
200         }
201         return thread_;
202     }
203 
ICEnabled()204     bool ICEnabled() const
205     {
206         return icEnabled_;
207     }
208 
209     void PushToNativePointerList(JSNativePointer *pointer);
210     void RemoveFromNativePointerList(JSNativePointer *pointer);
211     void PushToDeregisterModuleList(CString module);
212     void RemoveFromDeregisterModuleList(CString module);
213     bool ContainInDeregisterModuleList(CString module);
214     JSHandle<ecmascript::JSTaggedValue> GetAndClearEcmaUncaughtException() const;
215     JSHandle<ecmascript::JSTaggedValue> GetEcmaUncaughtException() const;
IsOptionalLogEnabled()216     bool IsOptionalLogEnabled() const
217     {
218         return optionalLogEnabled_;
219     }
220 
221     void Iterate(const RootVisitor &v, const RootRangeVisitor &rv);
222 
GetHeap()223     const Heap *GetHeap() const
224     {
225         return heap_;
226     }
227     void CollectGarbage(TriggerGCType gcType, GCReason reason = GCReason::OTHER) const;
228 
GetNativeAreaAllocator()229     NativeAreaAllocator *GetNativeAreaAllocator() const
230     {
231         return nativeAreaAllocator_.get();
232     }
233 
GetHeapRegionAllocator()234     HeapRegionAllocator *GetHeapRegionAllocator() const
235     {
236         return heapRegionAllocator_.get();
237     }
238 
GetChunk()239     Chunk *GetChunk() const
240     {
241         return const_cast<Chunk *>(&chunk_);
242     }
243     void ProcessNativeDelete(const WeakRootVisitor &visitor);
244     void ProcessReferences(const WeakRootVisitor &visitor);
245 
GetSnapshotEnv()246     SnapshotEnv *GetSnapshotEnv() const
247     {
248         return snapshotEnv_;
249     }
250 
GetJsDebuggerManager()251     tooling::JsDebuggerManager *GetJsDebuggerManager() const
252     {
253         return debuggerManager_;
254     }
255 
SetDeviceDisconnectCallback(DeviceDisconnectCallback cb)256     void SetDeviceDisconnectCallback(DeviceDisconnectCallback cb)
257     {
258         deviceDisconnectCallback_ = cb;
259     }
260 
GetDeviceDisconnectCallback()261     DeviceDisconnectCallback GetDeviceDisconnectCallback() const
262     {
263         return deviceDisconnectCallback_;
264     }
265 
SetEnableForceGC(bool enable)266     void SetEnableForceGC(bool enable)
267     {
268         options_.SetEnableForceGC(enable);
269     }
270 
SetNativePtrGetter(NativePtrGetter cb)271     void SetNativePtrGetter(NativePtrGetter cb)
272     {
273         nativePtrGetter_ = cb;
274     }
275 
GetNativePtrGetter()276     NativePtrGetter GetNativePtrGetter() const
277     {
278         return nativePtrGetter_;
279     }
280 
SetSourceMapCallback(SourceMapCallback cb)281     void SetSourceMapCallback(SourceMapCallback cb)
282     {
283         sourceMapCallback_ = cb;
284     }
285 
GetSourceMapCallback()286     SourceMapCallback GetSourceMapCallback() const
287     {
288         return sourceMapCallback_;
289     }
290 
SetSourceMapTranslateCallback(SourceMapTranslateCallback cb)291     void SetSourceMapTranslateCallback(SourceMapTranslateCallback cb)
292     {
293         sourceMapTranslateCallback_ = cb;
294     }
295 
GetSourceMapTranslateCallback()296     SourceMapTranslateCallback GetSourceMapTranslateCallback() const
297     {
298         return sourceMapTranslateCallback_;
299     }
300 
GetNativePointerListSize()301     size_t GetNativePointerListSize()
302     {
303         return nativePointerList_.size();
304     }
305 
GetNativePointerList()306     const CList<JSNativePointer *> GetNativePointerList() const
307     {
308         return nativePointerList_;
309     }
310 
SetResolveBufferCallback(ResolveBufferCallback cb)311     void SetResolveBufferCallback(ResolveBufferCallback cb)
312     {
313         resolveBufferCallback_ = cb;
314     }
315 
GetResolveBufferCallback()316     ResolveBufferCallback GetResolveBufferCallback() const
317     {
318         return resolveBufferCallback_;
319     }
320 
SetSearchHapPathCallBack(SearchHapPathCallBack cb)321     void SetSearchHapPathCallBack(SearchHapPathCallBack cb)
322     {
323         SearchHapPathCallBack_ = cb;
324     }
325 
GetSearchHapPathCallBack()326     SearchHapPathCallBack GetSearchHapPathCallBack() const
327     {
328         return SearchHapPathCallBack_;
329     }
330 
SetUnloadNativeModuleCallback(const UnloadNativeModuleCallback & cb)331     void SetUnloadNativeModuleCallback(const UnloadNativeModuleCallback &cb)
332     {
333         unloadNativeModuleCallback_ = cb;
334     }
335 
GetUnloadNativeModuleCallback()336     UnloadNativeModuleCallback GetUnloadNativeModuleCallback() const
337     {
338         return unloadNativeModuleCallback_;
339     }
340 
SetConcurrentCallback(ConcurrentCallback callback,void * data)341     void SetConcurrentCallback(ConcurrentCallback callback, void *data)
342     {
343         concurrentCallback_ = callback;
344         concurrentData_ = data;
345     }
346 
347     void TriggerConcurrentCallback(JSTaggedValue result, JSTaggedValue hint);
348 
349     void WorkersetInfo(EcmaVM *workerVm);
350 
351     EcmaVM *GetWorkerVm(uint32_t tid);
352 
353     bool DeleteWorker(EcmaVM *workerVm);
354 
355     bool SuspendWorkerVm(uint32_t tid);
356 
357     void ResumeWorkerVm(uint32_t tid);
358 
359     template<typename Callback>
EnumerateWorkerVm(Callback cb)360     void EnumerateWorkerVm(Callback cb)
361     {
362         // since there is a lock, so cannot mark function const
363         LockHolder lock(mutex_);
364         for (const auto &item : workerList_) {
365             cb(item.second);
366         }
367     }
368 
IsWorkerThread()369     bool IsWorkerThread() const
370     {
371         return options_.IsWorker();
372     }
373 
IsBundlePack()374     bool IsBundlePack() const
375     {
376         return isBundlePack_;
377     }
378 
SetIsBundlePack(bool value)379     void SetIsBundlePack(bool value)
380     {
381         isBundlePack_ = value;
382     }
383 
SetMockModuleList(const std::map<std::string,std::string> & list)384     void SetMockModuleList(const std::map<std::string, std::string> &list)
385     {
386         for (auto it = list.begin(); it != list.end(); ++it) {
387             mockModuleList_.emplace(it->first.c_str(), it->second.c_str());
388         }
389     }
390 
IsMockModule(const CString & moduleStr)391     inline bool IsMockModule(const CString &moduleStr) const
392     {
393         if (mockModuleList_.empty()) {
394             return false;
395         }
396         auto it = mockModuleList_.find(moduleStr);
397         if (it == mockModuleList_.end()) {
398             return false;
399         }
400         return true;
401     }
402 
GetMockModule(const CString & module)403     inline CString GetMockModule(const CString &module) const
404     {
405         auto it = mockModuleList_.find(module);
406         if (it == mockModuleList_.end()) {
407             LOG_ECMA(FATAL) << " Get Mock Module failed";
408         }
409         return it->second;
410     }
411 
412 #if defined(ECMASCRIPT_SUPPORT_HEAPPROFILER)
413     void DeleteHeapProfile();
414     HeapProfilerInterface *GetHeapProfile();
415     HeapProfilerInterface *GetOrNewHeapProfile();
416     void StartHeapTracking();
417     void StopHeapTracking();
418 #endif
419 
EnableReportModuleResolvingFailure()420     bool EnableReportModuleResolvingFailure() const
421     {
422         return options_.EnableReportModuleResolvingFailure();
423     }
424 
SetAssetPath(const CString & assetPath)425     void SetAssetPath(const CString &assetPath)
426     {
427         assetPath_ = assetPath;
428     }
429 
GetAssetPath()430     CString GetAssetPath() const
431     {
432         return assetPath_;
433     }
434 
SetBundleName(const CString & bundleName)435     void SetBundleName(const CString &bundleName)
436     {
437         bundleName_ = bundleName;
438     }
439 
GetBundleName()440     CString GetBundleName() const
441     {
442         return bundleName_;
443     }
444 
SetModuleName(const CString & moduleName)445     void SetModuleName(const CString &moduleName)
446     {
447         moduleName_ = moduleName;
448     }
449 
GetModuleName()450     CString GetModuleName() const
451     {
452         return moduleName_;
453     }
454 
455     std::pair<std::string, std::string> GetCurrentModuleInfo(bool needRecordName = false);
456 
457     void SetHmsModuleList(const std::vector<panda::HmsMap> &list);
458 
459     bool IsHmsModule(const CString &moduleStr) const;
460 
461     CString GetHmsModule(const CString &module) const;
462 
463 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
GetProfiler()464     CpuProfiler *GetProfiler() const
465     {
466         return profiler_;
467     }
468 
SetProfiler(CpuProfiler * profiler)469     void SetProfiler(CpuProfiler *profiler)
470     {
471         profiler_ = profiler;
472     }
473 #endif
474 
475 #if defined(ECMASCRIPT_SUPPORT_TRACING)
GetTracing()476     Tracing *GetTracing() const
477     {
478         return tracing_;
479     }
480 
SetTracing(Tracing * tracing)481     void SetTracing(Tracing *tracing)
482     {
483         tracing_ = tracing;
484     }
485 #endif
486 
GetPGOProfiler()487     std::shared_ptr<PGOProfiler> GetPGOProfiler() const
488     {
489         return pgoProfiler_;
490     }
491 
492     void PreFork();
493     void PostFork();
494 
495     // For Internal Native MethodLiteral.
496     JSTaggedValue GetMethodByIndex(MethodIndex idx);
497 
GetQuickFixManager()498     QuickFixManager *GetQuickFixManager() const
499     {
500         return quickFixManager_;
501     }
502 
503     JSTaggedValue FastCallAot(size_t actualNumArgs, JSTaggedType *args, const JSTaggedType *prevFp);
504 
505     void HandleUncaughtException(JSTaggedValue exception);
RegisterUncatchableErrorHandler(const UncatchableErrorHandler & uncatchableErrorHandler)506     void RegisterUncatchableErrorHandler(const UncatchableErrorHandler &uncatchableErrorHandler)
507     {
508         uncatchableErrorHandler_ = uncatchableErrorHandler;
509     }
510 
511     // handle uncatchable errors, such as oom
HandleUncatchableError()512     void HandleUncatchableError()
513     {
514         if (uncatchableErrorHandler_ != nullptr) {
515             panda::TryCatch trycatch(this);
516             uncatchableErrorHandler_(trycatch);
517         }
518     }
519 
520     void DumpCallTimeInfo();
521 
GetCallTimer()522     FunctionCallTimer *GetCallTimer() const
523     {
524         return callTimer_;
525     }
526 
GetEcmaStringTable()527     EcmaStringTable *GetEcmaStringTable() const
528     {
529         ASSERT(stringTable_ != nullptr);
530         return stringTable_;
531     }
532 
IncreaseCallDepth()533     void IncreaseCallDepth()
534     {
535         callDepth_++;
536     }
537 
DecreaseCallDepth()538     void DecreaseCallDepth()
539     {
540         ASSERT(callDepth_ > 0);
541         callDepth_--;
542     }
543 
IsTopLevelCallDepth()544     bool IsTopLevelCallDepth()
545     {
546         return callDepth_ == 0;
547     }
548 
SetProfilerState(bool state)549     void SetProfilerState(bool state)
550     {
551         isProfiling_ = state;
552     }
553 
GetProfilerState()554     bool GetProfilerState()
555     {
556         return isProfiling_;
557     }
558 
GetJSObjectResizingStrategy()559     JSObjectResizingStrategy *GetJSObjectResizingStrategy()
560     {
561         return strategy_;
562     }
563 
GetJit()564     Jit *GetJit()
565     {
566         return jit_;
567     }
568 
IsEnableJit()569     bool IsEnableJit() const
570     {
571         return isEnableJit_;
572     }
573 
GetWorkList()574     CMap<uint32_t, EcmaVM *> GetWorkList() const
575     {
576         return workerList_;
577     }
578 
SetEnableJit(bool state)579     void SetEnableJit(bool state)
580     {
581         isEnableJit_ = state;
582     }
583 
isOverLimit()584     bool isOverLimit() const
585     {
586         return overLimit_;
587     }
588 
SetOverLimit(bool state)589     void SetOverLimit(bool state)
590     {
591         overLimit_ = state;
592     }
593 protected:
594 
595     void PrintJSErrorInfo(const JSHandle<JSTaggedValue> &exceptionInfo) const;
596 
597 private:
598     void ClearBufferData();
599     void CheckStartCpuProfiler();
600 
601     // For Internal Native MethodLiteral.
602     void GenerateInternalNativeMethods();
603 
604     NO_MOVE_SEMANTIC(EcmaVM);
605     NO_COPY_SEMANTIC(EcmaVM);
606 
607     // VM startup states.
608     JSRuntimeOptions options_;
609     bool icEnabled_ {true};
610     bool initialized_ {false};
611     GCStats *gcStats_ {nullptr};
612     EcmaStringTable *stringTable_;
613 
614     // VM memory management.
615     std::unique_ptr<NativeAreaAllocator> nativeAreaAllocator_;
616     std::unique_ptr<HeapRegionAllocator> heapRegionAllocator_;
617     Chunk chunk_;
618     Heap *heap_ {nullptr};
619     ObjectFactory *factory_ {nullptr};
620     CList<JSNativePointer *> nativePointerList_;
621     // VM execution states.
622     JSThread *thread_ {nullptr};
623 
624     // VM resources.
625     SnapshotEnv *snapshotEnv_ {nullptr};
626     bool optionalLogEnabled_ {false};
627     // Debugger
628     tooling::JsDebuggerManager *debuggerManager_ {nullptr};
629     // merge abc
630     bool isBundlePack_ {true}; // isBundle means app compile mode is JSBundle
631 #if !WIN_OR_MAC_OR_IOS_PLATFORM
632     HeapProfilerInterface *heapProfile_ {nullptr};
633 #endif
634     CString assetPath_;
635     CString bundleName_;
636     CString moduleName_;
637     CList<CString> deregisterModuleList_;
638     CMap<CString, CString> mockModuleList_;
639     CMap<CString, HmsMap> hmsModuleList_;
640 
641     NativePtrGetter nativePtrGetter_ {nullptr};
642     SourceMapCallback sourceMapCallback_ {nullptr};
643     SourceMapTranslateCallback sourceMapTranslateCallback_ {nullptr};
644     void *loop_ {nullptr};
645 
646     // resolve path to get abc's buffer
647     ResolveBufferCallback resolveBufferCallback_ {nullptr};
648 
649     // delete the native module and dlclose so from NativeModuleManager
650     UnloadNativeModuleCallback unloadNativeModuleCallback_ {nullptr};
651 
652     // Concurrent taskpool callback and data
653     ConcurrentCallback concurrentCallback_ {nullptr};
654     void *concurrentData_ {nullptr};
655 
656     // serch happath callback
657     SearchHapPathCallBack SearchHapPathCallBack_ {nullptr};
658 
659     // vm parameter configurations
660     EcmaParamConfiguration ecmaParamConfiguration_;
661 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
662     CpuProfiler *profiler_ {nullptr};
663 #endif
664 #if defined(ECMASCRIPT_SUPPORT_TRACING)
665     Tracing *tracing_ {nullptr};
666 #endif
667     FunctionCallTimer *callTimer_ {nullptr};
668     JSObjectResizingStrategy *strategy_ {nullptr};
669 
670     // For Native MethodLiteral
671     static void *InternalMethodTable[static_cast<uint8_t>(MethodIndex::METHOD_END)];
672     CVector<JSTaggedValue> internalNativeMethods_;
673 
674     // For repair patch.
675     QuickFixManager *quickFixManager_ {nullptr};
676 
677     // PGO Profiler
678     std::shared_ptr<PGOProfiler> pgoProfiler_ {nullptr};
679     // c++ call js
680     size_t callDepth_ {0};
681 
682     bool isProfiling_ {false};
683 
684     DeviceDisconnectCallback deviceDisconnectCallback_ {nullptr};
685 
686     UncatchableErrorHandler uncatchableErrorHandler_ {nullptr};
687 
688     friend class Snapshot;
689     friend class SnapshotProcessor;
690     friend class ObjectFactory;
691     friend class ValueSerializer;
692     friend class panda::JSNApi;
693     friend class JSPandaFileExecutor;
694     friend class EcmaContext;
695     CMap<uint32_t, EcmaVM *> workerList_ {};
696     Mutex mutex_;
697     Jit *jit_ {nullptr};
698     bool isEnableJit_ {false};
699     bool overLimit_ {false};
700 };
701 }  // namespace ecmascript
702 }  // namespace panda
703 
704 #endif
705