• 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 <tuple>
20 
21 #include "ecmascript/base/config.h"
22 #include "ecmascript/ecma_string_table.h"
23 #include "ecmascript/global_handle_collection.h"
24 #include "ecmascript/js_handle.h"
25 #include "ecmascript/js_method.h"
26 #include "ecmascript/js_runtime_options.h"
27 #include "ecmascript/mem/c_containers.h"
28 #include "ecmascript/mem/c_string.h"
29 #include "ecmascript/mem/chunk_containers.h"
30 #include "ecmascript/mem/gc_stats.h"
31 #include "ecmascript/mem/heap.h"
32 #include "ecmascript/mem/object_xray.h"
33 #include "ecmascript/mem/space.h"
34 #include "ecmascript/platform/task.h"
35 #include "ecmascript/snapshot/mem/snapshot_serialize.h"
36 #include "ecmascript/tooling/interface/js_debugger_manager.h"
37 #include "ecmascript/tooling/backend/js_pt_extractor.h"
38 #include "include/panda_vm.h"
39 #include "libpandabase/macros.h"
40 
41 namespace panda {
42 namespace panda_file {
43 class File;
44 }  // namespace panda_file
45 
46 namespace ecmascript {
47 class GlobalEnv;
48 class ObjectFactory;
49 class RegExpParserCache;
50 class EcmaRuntimeStat;
51 class Heap;
52 class HeapTracker;
53 class JSNativePointer;
54 class Program;
55 class RegExpExecResultCache;
56 class JSPromise;
57 enum class PromiseRejectionEvent : uint8_t;
58 class JSPandaFileManager;
59 class JSPandaFile;
60 namespace job {
61 class MicroJobQueue;
62 }  // namespace job
63 
64 namespace tooling {
65 class JsDebuggerManager;
66 }  // namespace tooling
67 
68 template<typename T>
69 class JSHandle;
70 class JSArrayBuffer;
71 class JSFunction;
72 class Program;
73 class ModuleManager;
74 class EcmaModule;
75 class TSLoader;
76 struct BytecodeTranslationInfo;
77 using HostPromiseRejectionTracker = void (*)(const EcmaVM* vm,
78                                              const JSHandle<JSPromise> promise,
79                                              const JSHandle<JSTaggedValue> reason,
80                                              PromiseRejectionEvent operation,
81                                              void* data);
82 using PromiseRejectCallback = void (*)(void* info);
83 using IcuDeleteEntry = void(*)(void *pointer, void *data);
84 
85 enum class IcuFormatterType {
86     SimpleDateFormatDefault,
87     SimpleDateFormatDate,
88     SimpleDateFormatTime,
89     NumberFormatter,
90     Collator
91 };
92 
93 class EcmaVM : public PandaVM {
94 public:
Cast(PandaVM * object)95     static EcmaVM *Cast(PandaVM *object)
96     {
97         return reinterpret_cast<EcmaVM *>(object);
98     }
99 
100     static EcmaVM *Create(const JSRuntimeOptions &options);
101 
102     static bool Destroy(PandaVM *vm);
103 
104     explicit EcmaVM(JSRuntimeOptions options);
105 
106     static Expected<EcmaVM *, CString> Create([[maybe_unused]] Runtime *runtime);
107 
108     EcmaVM();
109 
110     ~EcmaVM() override;
111 
112     bool ExecuteFromPf(const std::string &filename, std::string_view entryPoint,
113                        const std::vector<std::string> &args, bool isModule = false);
114 
115     bool ExecuteFromBuffer(const void *buffer, size_t size, std::string_view entryPoint,
116                            const std::vector<std::string> &args, const std::string &filename = "");
117 
118     bool PUBLIC_API CollectInfoOfPandaFile(const std::string &filename, std::string_view entryPoint,
119                                            std::vector<BytecodeTranslationInfo> *infoList,
120                                            const panda_file::File *&pf);
121 
IsInitialized()122     bool IsInitialized() const
123     {
124         return vmInitialized_;
125     }
126 
GetFactory()127     ObjectFactory *GetFactory() const
128     {
129         return factory_;
130     }
131 
132     bool Initialize() override;
133 
134     bool InitializeFinish() override;
UninitializeThreads()135     void UninitializeThreads() override {}
PreStartup()136     void PreStartup() override {}
PreZygoteFork()137     void PreZygoteFork() override {}
PostZygoteFork()138     void PostZygoteFork() override {}
InitializeGC()139     void InitializeGC() override {}
StartGC()140     void StartGC() override {}
StopGC()141     void StopGC() override {}
142 
VisitVmRoots(const GCRootVisitor & visitor)143     void VisitVmRoots([[maybe_unused]] const GCRootVisitor &visitor) override {}
UpdateVmRefs()144     void UpdateVmRefs() override {}
145 
GetPandaVMType()146     PandaVMType GetPandaVMType() const override
147     {
148         return PandaVMType::ECMA_VM;
149     }
150 
GetLanguageContext()151     LanguageContext GetLanguageContext() const override
152     {
153         return Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ECMASCRIPT);
154     }
155 
GetHeapManager()156     panda::mem::HeapManager *GetHeapManager() const override
157     {
158         return nullptr;
159     }
160 
GetGC()161     panda::mem::GC *GetGC() const override
162     {
163         return nullptr;
164     }
165 
GetGCTrigger()166     panda::mem::GCTrigger *GetGCTrigger() const override
167     {
168         return nullptr;
169     }
170 
GetStringTable()171     StringTable *GetStringTable() const override
172     {
173         return nullptr;
174     }
175 
GetGCStats()176     panda::mem::GCStats *GetGCStats() const override
177     {
178         return nullptr;
179     }
180 
GetMemStats()181     panda::mem::MemStatsType *GetMemStats() const override
182     {
183         return nullptr;
184     }
185 
GetEcmaGCStats()186     GCStats *GetEcmaGCStats() const
187     {
188         return gcStats_;
189     }
190 
GetGlobalObjectStorage()191     panda::mem::GlobalObjectStorage *GetGlobalObjectStorage() const override
192     {
193         return nullptr;
194     }
195 
GetMonitorPool()196     MonitorPool *GetMonitorPool() const override
197     {
198         return nullptr;
199     }
200 
GetThreadManager()201     ThreadManager *GetThreadManager() const override
202     {
203         return nullptr;
204     }
205 
GetAssociatedThread()206     ManagedThread *GetAssociatedThread() const override
207     {
208         return thread_;
209     }
210 
GetAssociatedJSThread()211     JSThread *GetAssociatedJSThread() const
212     {
213         return thread_;
214     }
215 
GetCompiler()216     CompilerInterface *GetCompiler() const override
217     {
218         return nullptr;
219     }
220 
GetRendezvous()221     Rendezvous *GetRendezvous() const override
222     {
223         return nullptr;
224     }
225 
GetOOMErrorObject()226     ObjectHeader *GetOOMErrorObject() override
227     {
228         // preallocated OOM is not implemented for JS
229         UNREACHABLE();
230     }
231 
GetReferenceProcessor()232     panda::mem::ReferenceProcessor *GetReferenceProcessor() const override
233     {
234         return nullptr;
235     }
236 
GetOptions()237     const RuntimeOptions &GetOptions() const override
238     {
239         return Runtime::GetOptions();
240     }
241 
GetJSOptions()242     static const JSRuntimeOptions &GetJSOptions()
243     {
244         return options_;
245     }
246 
247     JSHandle<GlobalEnv> GetGlobalEnv() const;
248 
249     JSHandle<job::MicroJobQueue> GetMicroJobQueue() const;
250 
251     bool ExecutePromisePendingJob() const;
252 
GetRegExpParserCache()253     RegExpParserCache *GetRegExpParserCache() const
254     {
255         ASSERT(regExpParserCache_ != nullptr);
256         return regExpParserCache_;
257     }
258 
259     JSMethod *GetMethodForNativeFunction(const void *func);
260 
GetEcmaStringTable()261     EcmaStringTable *GetEcmaStringTable() const
262     {
263         ASSERT(stringTable_ != nullptr);
264         return stringTable_;
265     }
266 
GetJSThread()267     JSThread *GetJSThread() const
268     {
269 #if defined(ECMASCRIPT_ENABLE_THREAD_CHECK) && ECMASCRIPT_ENABLE_THREAD_CHECK
270         // Exclude GC thread
271         if (options_.IsEnableThreadCheck()) {
272             if (!Platform::GetCurrentPlatform()->IsInThreadPool(std::this_thread::get_id()) &&
273                 thread_->GetThreadId() != JSThread::GetCurrentThreadId()) {
274                     LOG(FATAL, RUNTIME) << "Fatal: ecma_vm cannot run in multi-thread!";
275             }
276         }
277 #endif
278         return thread_;
279     }
280 
GetJSThreadNoCheck()281     JSThread *GetJSThreadNoCheck() const
282     {
283         return thread_;
284     }
285 
ICEnable()286     bool ICEnable() const
287     {
288         return icEnable_;
289     }
290 
291     void PushToArrayDataList(JSNativePointer *array);
292     void RemoveArrayDataList(JSNativePointer *array);
293 
294     JSHandle<ecmascript::JSTaggedValue> GetAndClearEcmaUncaughtException() const;
295     JSHandle<ecmascript::JSTaggedValue> GetEcmaUncaughtException() const;
296     void EnableUserUncaughtErrorHandler();
297 
GetRuntimeStat()298     EcmaRuntimeStat *GetRuntimeStat() const
299     {
300         return runtimeStat_;
301     }
302 
303     void SetRuntimeStatEnable(bool flag);
304 
IsRuntimeStatEnabled()305     bool IsRuntimeStatEnabled() const
306     {
307         return runtimeStatEnabled_;
308     }
309 
IsOptionalLogEnabled()310     bool IsOptionalLogEnabled() const
311     {
312         return optionalLogEnabled_;
313     }
314 
315     void Iterate(const RootVisitor &v);
316 
GetHeap()317     const Heap *GetHeap() const
318     {
319         return heap_;
320     }
321 
322     void CollectGarbage(TriggerGCType gcType) const;
323 
324     void StartHeapTracking(HeapTracker *tracker);
325 
326     void StopHeapTracking();
327 
GetNativeAreaAllocator()328     NativeAreaAllocator *GetNativeAreaAllocator() const
329     {
330         return nativeAreaAllocator_.get();
331     }
332 
GetHeapRegionAllocator()333     HeapRegionAllocator *GetHeapRegionAllocator() const
334     {
335         return heapRegionAllocator_.get();
336     }
337 
GetChunk()338     Chunk *GetChunk() const
339     {
340         return const_cast<Chunk *>(&chunk_);
341     }
342     void ProcessNativeDelete(const WeakRootVisitor &v0);
343     void ProcessReferences(const WeakRootVisitor &v0);
344 
345     JSHandle<JSTaggedValue> GetModuleByName(JSHandle<JSTaggedValue> moduleName);
346 
347     void ExecuteModule(const std::string &moduleFile, std::string_view entryPoint,
348                        const std::vector<std::string> &args);
349 
GetModuleManager()350     ModuleManager *GetModuleManager() const
351     {
352         return moduleManager_;
353     }
354 
GetTSLoader()355     TSLoader *GetTSLoader() const
356     {
357         return tsLoader_;
358     }
359     void SetupRegExpResultCache();
360 
GetRegExpCache()361     JSHandle<JSTaggedValue> GetRegExpCache() const
362     {
363         return JSHandle<JSTaggedValue>(reinterpret_cast<uintptr_t>(&regexpCache_));
364     }
365 
SetRegExpCache(JSTaggedValue newCache)366     void SetRegExpCache(JSTaggedValue newCache)
367     {
368         regexpCache_ = newCache;
369     }
370 
GetJsDebuggerManager()371     tooling::JsDebuggerManager *GetJsDebuggerManager() const
372     {
373         return debuggerManager_;
374     }
375 
SetEnableForceGC(bool enable)376     void SetEnableForceGC(bool enable)
377     {
378         options_.SetEnableForceGC(enable);
379     }
380 
SetData(void * data)381     void SetData(void* data)
382     {
383         data_ = data;
384     }
385 
SetPromiseRejectCallback(PromiseRejectCallback cb)386     void SetPromiseRejectCallback(PromiseRejectCallback cb)
387     {
388         promiseRejectCallback_ = cb;
389     }
390 
GetPromiseRejectCallback()391     PromiseRejectCallback GetPromiseRejectCallback() const
392     {
393         return promiseRejectCallback_;
394     }
395 
SetHostPromiseRejectionTracker(HostPromiseRejectionTracker cb)396     void SetHostPromiseRejectionTracker(HostPromiseRejectionTracker cb)
397     {
398         hostPromiseRejectionTracker_ = cb;
399     }
400 
PromiseRejectionTracker(const JSHandle<JSPromise> & promise,const JSHandle<JSTaggedValue> & reason,PromiseRejectionEvent operation)401     void PromiseRejectionTracker(const JSHandle<JSPromise> &promise,
402                                  const JSHandle<JSTaggedValue> &reason, PromiseRejectionEvent operation)
403     {
404         if (hostPromiseRejectionTracker_ != nullptr) {
405             hostPromiseRejectionTracker_(this, promise, reason, operation, data_);
406         }
407     }
408 
409     void SetConstpool(const JSPandaFile *jsPandaFile, JSTaggedValue constpool);
410 
411     JSTaggedValue FindConstpool(const JSPandaFile *jsPandaFile);
412 
413     // For icu objects cache
414     void SetIcuFormatterToCache(IcuFormatterType type, const std::string &locale, void *icuObj,
415                                 IcuDeleteEntry deleteEntry = nullptr)
416     {
417         EcmaVM::IcuFormatter icuFormatter = IcuFormatter(locale, icuObj, deleteEntry);
418         icuObjCache_.insert_or_assign(type, std::move(icuFormatter));
419     }
420 
GetIcuFormatterFromCache(IcuFormatterType type,std::string locale)421     void *GetIcuFormatterFromCache(IcuFormatterType type, std::string locale)
422     {
423         auto iter = icuObjCache_.find(type);
424         if (iter != icuObjCache_.end()) {
425             EcmaVM::IcuFormatter icuFormatter = iter->second;
426             if (icuFormatter.locale == locale) {
427                 return icuFormatter.icuObj;
428             }
429         }
430         return nullptr;
431     }
432 
ClearIcuCache()433     void ClearIcuCache()
434     {
435         auto iter = icuObjCache_.begin();
436         while (iter != icuObjCache_.end()) {
437             EcmaVM::IcuFormatter icuFormatter = iter->second;
438             IcuDeleteEntry deleteEntry = icuFormatter.deleteEntry;
439             if (deleteEntry != nullptr) {
440                 deleteEntry(icuFormatter.icuObj, this);
441             }
442             iter->second = EcmaVM::IcuFormatter{};
443             iter++;
444         }
445     }
446 
447 protected:
CheckEntrypointSignature(Method * entrypoint)448     bool CheckEntrypointSignature([[maybe_unused]] Method *entrypoint) override
449     {
450         return true;
451     }
452 
453     Expected<int, Runtime::Error> InvokeEntrypointImpl(Method *entrypoint,
454                                                        const std::vector<std::string> &args) override;
455 
456     void HandleUncaughtException(ObjectHeader *exception) override;
457 
458     void PrintJSErrorInfo(const JSHandle<JSTaggedValue> &exceptionInfo);
459 
460 private:
461     bool IsFrameworkPandaFile(std::string_view filename) const;
462 
463     void SetGlobalEnv(GlobalEnv *global);
464 
465     void SetMicroJobQueue(job::MicroJobQueue *queue);
466 
467     bool Execute(const JSPandaFile *jsPandaFile, std::string_view entryPoint, const std::vector<std::string> &args);
468 
469     Expected<int, Runtime::Error> InvokeEcmaEntrypoint(const JSPandaFile *jsPandaFile, const CString &methodName,
470                                                        const std::vector<std::string> &args);
471 
472     void InitializeEcmaScriptRunStat();
473 
474     void RedirectMethod(const panda_file::File &pf);
475 
476     bool VerifyFilePath(const CString &filePath) const;
477 
478     void ClearBufferData();
479 
480     void ClearNativeMethodsData();
481 
482     NO_MOVE_SEMANTIC(EcmaVM);
483     NO_COPY_SEMANTIC(EcmaVM);
484 
485     // Useless/deprecated fields in the future:
486     bool isTestMode_ {false};
487 
488     // VM startup states.
489     PUBLIC_API static JSRuntimeOptions options_;
490     bool icEnable_ {true};
491     bool vmInitialized_ {false};
492     GCStats *gcStats_ {nullptr};
493     bool snapshotSerializeEnable_ {false};
494     bool snapshotDeserializeEnable_ {false};
495     bool isUncaughtExceptionRegistered_ {false};
496 
497     // VM memory management.
498     EcmaStringTable *stringTable_ {nullptr};
499     std::unique_ptr<NativeAreaAllocator> nativeAreaAllocator_;
500     std::unique_ptr<HeapRegionAllocator> heapRegionAllocator_;
501     Chunk chunk_;
502     Heap *heap_ {nullptr};
503     ObjectFactory *factory_ {nullptr};
504     ChunkVector<JSNativePointer *> arrayBufferDataList_;
505 
506     // VM execution states.
507     JSThread *thread_ {nullptr};
508     RegExpParserCache *regExpParserCache_ {nullptr};
509     JSTaggedValue globalEnv_ {JSTaggedValue::Hole()};
510     JSTaggedValue regexpCache_ {JSTaggedValue::Hole()};
511     JSTaggedValue microJobQueue_ {JSTaggedValue::Hole()};
512     bool runtimeStatEnabled_ {false};
513     EcmaRuntimeStat *runtimeStat_ {nullptr};
514 
515     // App framework resources.
516     JSTaggedValue frameworkProgram_ {JSTaggedValue::Hole()};
517     CString frameworkAbcFileName_;
518     const JSPandaFile *frameworkPandaFile_ {nullptr};
519     ChunkVector<JSMethod *> frameworkProgramMethods_;
520     CMap<const JSPandaFile *, JSTaggedValue> pandaFileWithConstpool_ {};
521 
522     // VM resources.
523     CString snapshotFileName_;
524     ChunkUnorderedMap<const void *, JSMethod *> nativeMethodMaps_;
525     ModuleManager *moduleManager_ {nullptr};
526     TSLoader *tsLoader_ {nullptr};
527     bool optionalLogEnabled_ {false};
528 
529     // Debugger
530     tooling::JsDebuggerManager *debuggerManager_ {nullptr};
531 
532     // Registered Callbacks
533     PromiseRejectCallback promiseRejectCallback_ {nullptr};
534     HostPromiseRejectionTracker hostPromiseRejectionTracker_ {nullptr};
535     void* data_ {nullptr};
536 
537     // For icu objects cache
538     struct IcuFormatter {
539         std::string locale;
540         void *icuObj {nullptr};
541         IcuDeleteEntry deleteEntry {nullptr};
542 
543         IcuFormatter() = default;
544         IcuFormatter(const std::string &locale, void *icuObj, IcuDeleteEntry deleteEntry = nullptr)
localeIcuFormatter545             : locale(locale), icuObj(icuObj), deleteEntry(deleteEntry) {}
546     };
547     std::unordered_map<IcuFormatterType, IcuFormatter> icuObjCache_;
548 
549     friend class SnapShotSerialize;
550     friend class ObjectFactory;
551     friend class ValueSerializer;
552     friend class panda::JSNApi;
553 };
554 }  // namespace ecmascript
555 }  // namespace panda
556 
557 #endif
558