• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2025 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 PANDA_PLUGINS_ETS_RUNTIME_ETS_VM_H_
17 #define PANDA_PLUGINS_ETS_RUNTIME_ETS_VM_H_
18 
19 #include <atomic>
20 #include <optional>
21 #include <random>
22 #include <string>
23 #include <vector>
24 
25 #include <libpandafile/include/source_lang_enum.h>
26 
27 #include "include/mem/panda_smart_pointers.h"
28 #include "libpandabase/macros.h"
29 #include "libpandabase/mem/mem.h"
30 #include "libpandabase/utils/expected.h"
31 #include "libpandabase/os/mutex.h"
32 #include "runtime/coroutines/stackful_coroutine.h"
33 #include "runtime/include/compiler_interface.h"
34 #include "runtime/include/external_callback_poster.h"
35 #include "runtime/include/gc_task.h"
36 #include "runtime/include/language_context.h"
37 #include "runtime/include/managed_thread.h"
38 #include "runtime/include/mem/panda_containers.h"
39 #include "runtime/include/mem/panda_string.h"
40 #include "runtime/include/method.h"
41 #include "runtime/include/object_header.h"
42 #include "runtime/include/panda_vm.h"
43 #include "runtime/include/runtime_options.h"
44 #include "runtime/include/runtime.h"
45 #include "runtime/mem/gc/gc_stats.h"
46 #include "runtime/mem/gc/gc_trigger.h"
47 #include "runtime/mem/gc/gc.h"
48 #include "runtime/mem/gc/reference-processor/reference_processor.h"
49 #include "runtime/mem/heap_manager.h"
50 #include "runtime/mem/memory_manager.h"
51 #include "runtime/mem/refstorage/global_object_storage.h"
52 #include "runtime/mem/rendezvous.h"
53 #include "runtime/monitor_pool.h"
54 #include "runtime/string_table.h"
55 #include "runtime/thread_manager.h"
56 #include "plugins/ets/runtime/ets_class_linker.h"
57 #include "plugins/ets/runtime/ets_coroutine.h"
58 #include "runtime/coroutines/coroutine_manager.h"
59 #include "plugins/ets/runtime/ani/ani.h"
60 #include "plugins/ets/runtime/ets_native_library_provider.h"
61 #include "plugins/ets/runtime/napi/ets_napi.h"
62 #include "plugins/ets/runtime/types/ets_object.h"
63 #include "plugins/ets/runtime/ets_handle_scope.h"
64 #include "plugins/ets/runtime/ets_handle.h"
65 #include "plugins/ets/runtime/mem/root_provider.h"
66 #include "plugins/ets/runtime/ets_object_state_table.h"
67 #include "plugins/ets/runtime/finalreg/finalization_registry_manager.h"
68 
69 namespace ark::ets {
70 class DoubleToStringCache;
71 class FloatToStringCache;
72 class LongToStringCache;
73 class EtsAbcRuntimeLinker;
74 class EtsFinalizableWeakRef;
75 
76 using WalkEventLoopCallback = std::function<void(void *, void *)>;
77 
78 enum class EventLoopRunMode : int { RUN_DEFAULT = 0, RUN_ONCE, RUN_NOWAIT };
79 
80 class PandaEtsVM final : public PandaVM, public EtsVM, public ani_vm {  // NOLINT(fuchsia-multiple-inheritance)
81 public:
82     static Expected<PandaEtsVM *, PandaString> Create(Runtime *runtime, const RuntimeOptions &options);
83     static bool Destroy(PandaEtsVM *vm);
84 
85     ~PandaEtsVM() override;
86 
87     PANDA_PUBLIC_API static PandaEtsVM *GetCurrent();
88 
89     /**
90      * @brief Create TaskManager if needed and set it to runtime
91      * @note It's temporary solution, TaskManager will be created outside VM in the future
92      *
93      * @param options runtime options
94      *
95      * @return true if TaskManager was created, false - otherwise
96      */
97     static bool CreateTaskManagerIfNeeded(const RuntimeOptions &options);
98 
99     bool Initialize() override;
100     bool InitializeFinish() override;
101 
102     void PreStartup() override;
103     void PreZygoteFork() override;
104     void PostZygoteFork() override;
105     void InitializeGC() override;
106     void StartGC() override;
107     void StopGC() override;
108     void VisitVmRoots(const GCRootVisitor &visitor) override;
109     void UpdateVmRefs(const GCRootUpdater &gcRootUpdater) override;
110     void UninitializeThreads() override;
111 
112     void HandleReferences(const GCTask &task, const mem::GC::ReferenceClearPredicateT &pred) override;
113     void HandleGCRoutineInMutator() override;
114     void HandleGCFinished() override;
115 
GetOptions()116     const RuntimeOptions &GetOptions() const override
117     {
118         return Runtime::GetOptions();
119     }
120 
GetLanguageContext()121     LanguageContext GetLanguageContext() const override
122     {
123         return Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS);
124     }
125 
ResolveString(const panda_file::File & pf,panda_file::File::EntityId id)126     coretypes::String *ResolveString(const panda_file::File &pf, panda_file::File::EntityId id) override
127     {
128         coretypes::String *str = GetStringTable()->GetInternalStringFast(pf, id);
129         if (str != nullptr) {
130             return str;
131         }
132         str = GetStringTable()->GetOrInternInternalString(pf, id, GetLanguageContext());
133         return str;
134     }
135 
ResolveString(Frame * frame,panda_file::File::EntityId id)136     coretypes::String *ResolveString(Frame *frame, panda_file::File::EntityId id) override
137     {
138         return PandaEtsVM::ResolveString(*frame->GetMethod()->GetPandaFile(), id);
139     }
140 
141     coretypes::String *CreateString(Method *ctor, ObjectHeader *obj) override;
142 
GetRuntime()143     Runtime *GetRuntime() const
144     {
145         return runtime_;
146     }
147 
GetHeapManager()148     mem::HeapManager *GetHeapManager() const override
149     {
150         ASSERT(mm_ != nullptr);
151         return mm_->GetHeapManager();
152     }
153 
GetMemStats()154     mem::MemStatsType *GetMemStats() const override
155     {
156         ASSERT(mm_ != nullptr);
157         return mm_->GetMemStats();
158     }
159 
GetGC()160     mem::GC *GetGC() const override
161     {
162         ASSERT(mm_ != nullptr);
163         return mm_->GetGC();
164     }
165 
GetGCTrigger()166     mem::GCTrigger *GetGCTrigger() const override
167     {
168         ASSERT(mm_ != nullptr);
169         return mm_->GetGCTrigger();
170     }
171 
GetGCStats()172     mem::GCStats *GetGCStats() const override
173     {
174         ASSERT(mm_ != nullptr);
175         return mm_->GetGCStats();
176     }
177 
GetClassLinker()178     EtsClassLinker *GetClassLinker() const
179     {
180         return classLinker_.get();
181     }
182 
GetEtsClassLinkerExtension()183     EtsClassLinkerExtension *GetEtsClassLinkerExtension() const
184     {
185         return classLinker_.get()->GetEtsClassLinkerExtension();
186     }
187 
GetGlobalObjectStorage()188     mem::GlobalObjectStorage *GetGlobalObjectStorage() const override
189     {
190         ASSERT(mm_ != nullptr);
191         return mm_->GetGlobalObjectStorage();
192     }
193 
194     void DeleteGlobalRef(ets_object globalRef);
195 
196     void DeleteWeakGlobalRef(ets_weak weakRef);
197 
GetReferenceProcessor()198     mem::ReferenceProcessor *GetReferenceProcessor() const override
199     {
200         ASSERT(referenceProcessor_ != nullptr);
201         return referenceProcessor_;
202     }
203 
GetStringTable()204     StringTable *GetStringTable() const override
205     {
206         return stringTable_;
207     }
208 
GetMonitorPool()209     MonitorPool *GetMonitorPool() const override
210     {
211         return monitorPool_;
212     }
213 
GetAssociatedThread()214     ManagedThread *GetAssociatedThread() const override
215     {
216         return ManagedThread::GetCurrent();
217     }
218 
GetThreadManager()219     ThreadManager *GetThreadManager() const override
220     {
221         return coroutineManager_;
222     }
223 
GetFinalizationRegistryManager()224     FinalizationRegistryManager *GetFinalizationRegistryManager() const
225     {
226         return finalizationRegistryManager_;
227     }
228 
GetCoroutineManager()229     CoroutineManager *GetCoroutineManager() const
230     {
231         return static_cast<CoroutineManager *>(GetThreadManager());
232     }
233 
GetRendezvous()234     Rendezvous *GetRendezvous() const override
235     {
236         return rendezvous_;
237     }
238 
GetCompiler()239     CompilerInterface *GetCompiler() const override
240     {
241         return compiler_;
242     }
243 
244     PANDA_PUBLIC_API ObjectHeader *GetOOMErrorObject() override;
245 
246     PANDA_PUBLIC_API ObjectHeader *GetNullValue() const;
247 
GetCompilerRuntimeInterface()248     compiler::RuntimeInterface *GetCompilerRuntimeInterface() const override
249     {
250         return runtimeIface_;
251     }
252 
253     bool LoadNativeLibrary(EtsEnv *env, const PandaString &name, bool shouldVerifyPermission,
254                            const PandaString &fileName);
255 
256     void ResolveNativeMethod(Method *method);
257 
FromEtsVM(EtsVM * vm)258     static PandaEtsVM *FromEtsVM(EtsVM *vm)
259     {
260         return static_cast<PandaEtsVM *>(vm);
261     }
262 
FromAniVM(ani_vm * vm)263     static PandaEtsVM *FromAniVM(ani_vm *vm)
264     {
265         return static_cast<PandaEtsVM *>(vm);
266     }
267 
268     [[noreturn]] static void Abort(const char *message = nullptr);
269 
GetRandomEngine()270     std::mt19937 &GetRandomEngine()
271     {
272         ASSERT(randomEngine_);
273         return *randomEngine_;
274     }
275 
IsStaticProfileEnabled()276     bool IsStaticProfileEnabled() const override
277     {
278         return true;
279     }
280 
CleanupCompiledFrameResources(Frame * frame)281     void CleanupCompiledFrameResources(Frame *frame) override
282     {
283         auto *coro = EtsCoroutine::GetCurrent();
284         auto *ifaces = coro->GetExternalIfaceTable();
285         if (ifaces->GetClearInteropHandleScopesFunction()) {
286             ifaces->GetClearInteropHandleScopesFunction()(frame);
287         }
288     }
289 
GetAniBindMutex()290     os::memory::Mutex &GetAniBindMutex()
291     {
292         return aniBindMutex_;
293     }
294 
GetAtomicsMutex()295     os::memory::Mutex &GetAtomicsMutex()
296     {
297         return atomicsMutex_;
298     }
299 
SupportGCSinglePassCompaction()300     bool SupportGCSinglePassCompaction() const override
301     {
302         return true;
303     }
304 
GetDoubleToStringCache()305     DoubleToStringCache *GetDoubleToStringCache()
306     {
307         return doubleToStringCache_;
308     }
309 
GetFloatToStringCache()310     FloatToStringCache *GetFloatToStringCache()
311     {
312         return floatToStringCache_;
313     }
314 
GetLongToStringCache()315     LongToStringCache *GetLongToStringCache()
316     {
317         return longToStringCache_;
318     }
319 
GetDoubleToStringCacheOffset()320     static constexpr uint32_t GetDoubleToStringCacheOffset()
321     {
322         return MEMBER_OFFSET(PandaEtsVM, doubleToStringCache_);
323     }
324 
325     void RegisterFinalizerForObject(EtsCoroutine *coro, const EtsHandle<EtsObject> &object, void (*finalizer)(void *),
326                                     void *finalizerArg);
327 
328     void CleanFinalizableReferenceList();
329 
330     void BeforeShutdown() override;
331 
332     /**
333      * @brief Method creates CallbackPosterFactory with your implementation. Here we use template to avoid
334      * usage of InternalAllocator outside the virtual machine.
335      */
336     template <class FactoryImpl, class... Args>
CreateCallbackPosterFactory(Args...args)337     void CreateCallbackPosterFactory(Args... args)
338     {
339         static_assert(std::is_base_of_v<CallbackPosterFactoryIface, FactoryImpl>);
340         static_assert(std::is_constructible_v<FactoryImpl, Args...>);
341         ASSERT(callbackPosterFactory_ == nullptr);
342         callbackPosterFactory_ = MakePandaUnique<FactoryImpl>(args...);
343     }
344 
345     /// @brief Method creates CallBackPoster using factory.
CreateCallbackPoster()346     PandaUniquePtr<CallbackPoster> CreateCallbackPoster()
347     {
348         if (callbackPosterFactory_ == nullptr) {
349             return nullptr;
350         }
351         return callbackPosterFactory_->CreatePoster();
352     }
353 
354     using RunEventLoopFunction = std::function<void(EventLoopRunMode)>;
355 
SetRunEventLoopFunction(RunEventLoopFunction && cb)356     void SetRunEventLoopFunction(RunEventLoopFunction &&cb)
357     {
358         ASSERT(!runEventLoop_);
359         runEventLoop_ = std::move(cb);
360     }
361 
RunEventLoop(EventLoopRunMode mode)362     void RunEventLoop(EventLoopRunMode mode)
363     {
364         if (runEventLoop_) {
365             runEventLoop_(mode);
366         }
367     }
368 
369     using WalkEventLoopFunction = std::function<void(WalkEventLoopCallback &, void *)>;
SetWalkEventLoopFunction(WalkEventLoopFunction && cb)370     void SetWalkEventLoopFunction(WalkEventLoopFunction &&cb)
371     {
372         ASSERT(!walkEventLoop_);
373         walkEventLoop_ = std::move(cb);
374     }
375 
WalkEventLoop(WalkEventLoopCallback & callback,void * args)376     void WalkEventLoop(WalkEventLoopCallback &callback, void *args)
377     {
378         if (walkEventLoop_) {
379             walkEventLoop_(callback, args);
380         }
381     }
382 
GetEtsObjectStateTable()383     EtsObjectStateTable *GetEtsObjectStateTable() const
384     {
385         return objStateTable_.get();
386     }
387 
FreeInternalResources()388     void FreeInternalResources() override
389     {
390         objStateTable_->DeflateInfo();
391     }
392 
393     /// @brief Adds failed job to an internal storage
394     void AddUnhandledFailedJob(EtsJob *job);
395 
396     /// @brief Removes failed job from internal storage
397     void RemoveUnhandledFailedJob(EtsJob *job);
398 
399     /// @brief Invokes managed method to apply custom handler on stored failed jobs
400     void ListUnhandledFailedJobs();
401 
402     /// @brief Adds rejected promise to an internal storage
403     void AddUnhandledRejectedPromise(EtsPromise *promise);
404 
405     /// @brief Removes rejected promise from internal storage
406     void RemoveUnhandledRejectedPromise(EtsPromise *promise);
407 
408     /// @brief Invokes managed method to apply custom handler on stored rejected promises
409     void ListUnhandledRejectedPromises();
410 
411     PANDA_PUBLIC_API void AddRootProvider(mem::RootProvider *provider);
412     PANDA_PUBLIC_API void RemoveRootProvider(mem::RootProvider *provider);
413 
414     /// @brief Create application `AbcRuntimeLinker` in managed scope.
415     ClassLinkerContext *CreateApplicationRuntimeLinker(const PandaVector<PandaString> &abcFiles);
416 
417     /// @brief print stack and exit the program
418     [[noreturn]] void HandleUncaughtException() override;
419 
420 protected:
421     bool CheckEntrypointSignature(Method *entrypoint) override;
422     Expected<int, Runtime::Error> InvokeEntrypointImpl(Method *entrypoint,
423                                                        const std::vector<std::string> &args) override;
424 
425 private:
426     /**
427      * @brief Update a VM root that has been moved by GC.
428      * @param ref a reference to update, should hold an ObjectHeader pointer
429      * @tparam REF_CAN_BE_NULL true iff it is legal for @param ref to hold a null pointer
430      */
431     template <bool REF_CAN_BE_NULL>
432     static void UpdateMovedVmRef(Value &ref, const GCRootUpdater &gcRootUpdater);
433 
434     static void UpdateManagedEntrypointArgRefs(EtsCoroutine *coroutine, const GCRootUpdater &gcRootUpdater);
435 
InitializeRandomEngine()436     void InitializeRandomEngine()
437     {
438         ASSERT(!randomEngine_);
439         std::random_device rd;
440         randomEngine_.emplace(rd());
441     }
442 
443     explicit PandaEtsVM(Runtime *runtime, const RuntimeOptions &options, mem::MemoryManager *mm);
444 
445     void AddUnhandledObjectImpl(PandaUnorderedSet<EtsObject *> &unhandledObjects, EtsObject *object);
446     void RemoveUnhandledObjectImpl(PandaUnorderedSet<EtsObject *> &unhandledObjects, EtsObject *object);
447 
448     Runtime *runtime_ {nullptr};
449     mem::MemoryManager *mm_ {nullptr};
450     PandaUniquePtr<EtsClassLinker> classLinker_;
451     mem::ReferenceProcessor *referenceProcessor_ {nullptr};
452     PandaVector<ObjectHeader *> gcRoots_;
453     Rendezvous *rendezvous_ {nullptr};
454     CompilerInterface *compiler_ {nullptr};
455     StringTable *stringTable_ {nullptr};
456     MonitorPool *monitorPool_ {nullptr};
457     FinalizationRegistryManager *finalizationRegistryManager_ {nullptr};
458     CoroutineManager *coroutineManager_ {nullptr};
459     mem::Reference *oomObjRef_ {nullptr};
460     compiler::RuntimeInterface *runtimeIface_ {nullptr};
461     mem::Reference *nullValueRef_ {nullptr};
462     mem::Reference *finalizableWeakRefList_ {nullptr};
463     os::memory::Mutex finalizableWeakRefListLock_;
464     NativeLibraryProvider nativeLibraryProvider_;
465     PandaUniquePtr<CallbackPosterFactoryIface> callbackPosterFactory_;
466     os::memory::Mutex rootProviderlock_;
467     PandaUnorderedSet<mem::RootProvider *> rootProviders_ GUARDED_BY(rootProviderlock_);
468     os::memory::Mutex aniBindMutex_;
469     // optional for lazy initialization
470     std::optional<std::mt19937> randomEngine_;
471     // for JS Atomics
472     os::memory::Mutex atomicsMutex_;
473     DoubleToStringCache *doubleToStringCache_ {nullptr};
474     FloatToStringCache *floatToStringCache_ {nullptr};
475     LongToStringCache *longToStringCache_ {nullptr};
476     os::memory::Mutex unhandledMutex_;
477     PandaUnorderedSet<EtsObject *> unhandledFailedJobs_;
478     PandaUnorderedSet<EtsObject *> unhandledRejectedPromises_;
479 
480     PandaUniquePtr<EtsObjectStateTable> objStateTable_ {nullptr};
481     RunEventLoopFunction runEventLoop_ = nullptr;
482     WalkEventLoopFunction walkEventLoop_ = nullptr;
483 
484     size_t preForkWorkerCount_ = 0;
485 
486     NO_MOVE_SEMANTIC(PandaEtsVM);
487     NO_COPY_SEMANTIC(PandaEtsVM);
488 
489     friend class mem::Allocator;
490 };
491 
492 }  // namespace ark::ets
493 
494 #endif  // !PANDA_PLUGINS_ETS_RUNTIME_ETS_VM_H_
495