• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2024 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 "libpandabase/macros.h"
28 #include "libpandabase/mem/mem.h"
29 #include "libpandabase/utils/expected.h"
30 #include "libpandabase/os/mutex.h"
31 #include "runtime/include/compiler_interface.h"
32 #include "runtime/include/external_callback_poster.h"
33 #include "runtime/include/gc_task.h"
34 #include "runtime/include/language_context.h"
35 #include "runtime/include/managed_thread.h"
36 #include "runtime/include/mem/panda_containers.h"
37 #include "runtime/include/mem/panda_string.h"
38 #include "runtime/include/method.h"
39 #include "runtime/include/object_header.h"
40 #include "runtime/include/panda_vm.h"
41 #include "runtime/include/runtime_options.h"
42 #include "runtime/include/runtime.h"
43 #include "runtime/mem/gc/gc_stats.h"
44 #include "runtime/mem/gc/gc_trigger.h"
45 #include "runtime/mem/gc/gc.h"
46 #include "runtime/mem/gc/reference-processor/reference_processor.h"
47 #include "runtime/mem/heap_manager.h"
48 #include "runtime/mem/memory_manager.h"
49 #include "runtime/mem/refstorage/global_object_storage.h"
50 #include "runtime/mem/rendezvous.h"
51 #include "runtime/monitor_pool.h"
52 #include "runtime/string_table.h"
53 #include "runtime/thread_manager.h"
54 #include "plugins/ets/runtime/ets_class_linker.h"
55 #include "plugins/ets/runtime/ets_coroutine.h"
56 #include "runtime/coroutines/coroutine_manager.h"
57 #include "plugins/ets/runtime/ets_native_library_provider.h"
58 #include "plugins/ets/runtime/napi/ets_napi.h"
59 #include "plugins/ets/runtime/types/ets_object.h"
60 #include "plugins/ets/runtime/job_queue.h"
61 #include "plugins/ets/runtime/ets_handle_scope.h"
62 #include "plugins/ets/runtime/ets_handle.h"
63 
64 namespace ark::ets {
65 
66 class DoubleToStringCache;
67 class FloatToStringCache;
68 class LongToStringCache;
69 class EtsFinalizableWeakRef;
70 
71 class PandaEtsVM final : public PandaVM, public EtsVM {  // NOLINT(fuchsia-multiple-inheritance)
72 public:
73     static Expected<PandaEtsVM *, PandaString> Create(Runtime *runtime, const RuntimeOptions &options);
74     static bool Destroy(PandaEtsVM *vm);
75 
76     ~PandaEtsVM() override;
77 
78     PANDA_PUBLIC_API static PandaEtsVM *GetCurrent();
79 
80     /**
81      * @brief Create TaskManager if needed and set it to runtime
82      * @note It's temporary solution, TaskManager will be created outside VM in the future
83      *
84      * @param options runtime options
85      *
86      * @return true if TaskManager was created, false - otherwise
87      */
88     static bool CreateTaskManagerIfNeeded(const RuntimeOptions &options);
89 
90     bool Initialize() override;
91     bool InitializeFinish() override;
92 
93     void PreStartup() override;
94     void PreZygoteFork() override;
95     void PostZygoteFork() override;
96     void InitializeGC() override;
97     void StartGC() override;
98     void StopGC() override;
99     void SweepVmRefs(const GCObjectVisitor &gcObjectVisitor) override;
100     void VisitVmRoots(const GCRootVisitor &visitor) override;
101     void UpdateVmRefs() override;
102     void UninitializeThreads() override;
103 
104     void HandleReferences(const GCTask &task, const mem::GC::ReferenceClearPredicateT &pred) override;
105     void HandleGCRoutineInMutator() override;
106     void HandleGCFinished() override;
107 
GetOptions()108     const RuntimeOptions &GetOptions() const override
109     {
110         return Runtime::GetOptions();
111     }
112 
GetLanguageContext()113     LanguageContext GetLanguageContext() const override
114     {
115         return Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS);
116     }
117 
ResolveString(const panda_file::File & pf,panda_file::File::EntityId id)118     coretypes::String *ResolveString(const panda_file::File &pf, panda_file::File::EntityId id) override
119     {
120         coretypes::String *str = GetStringTable()->GetInternalStringFast(pf, id);
121         if (str != nullptr) {
122             return str;
123         }
124         str = GetStringTable()->GetOrInternInternalString(pf, id, GetLanguageContext());
125         return str;
126     }
127 
ResolveString(Frame * frame,panda_file::File::EntityId id)128     coretypes::String *ResolveString(Frame *frame, panda_file::File::EntityId id) override
129     {
130         return PandaEtsVM::ResolveString(*frame->GetMethod()->GetPandaFile(), id);
131     }
132 
133     coretypes::String *CreateString(Method *ctor, ObjectHeader *obj) override;
134 
GetRuntime()135     Runtime *GetRuntime() const
136     {
137         return runtime_;
138     }
139 
GetHeapManager()140     mem::HeapManager *GetHeapManager() const override
141     {
142         ASSERT(mm_ != nullptr);
143         return mm_->GetHeapManager();
144     }
145 
GetMemStats()146     mem::MemStatsType *GetMemStats() const override
147     {
148         ASSERT(mm_ != nullptr);
149         return mm_->GetMemStats();
150     }
151 
GetGC()152     mem::GC *GetGC() const override
153     {
154         ASSERT(mm_ != nullptr);
155         return mm_->GetGC();
156     }
157 
GetGCTrigger()158     mem::GCTrigger *GetGCTrigger() const override
159     {
160         ASSERT(mm_ != nullptr);
161         return mm_->GetGCTrigger();
162     }
163 
GetGCStats()164     mem::GCStats *GetGCStats() const override
165     {
166         ASSERT(mm_ != nullptr);
167         return mm_->GetGCStats();
168     }
169 
GetClassLinker()170     EtsClassLinker *GetClassLinker() const
171     {
172         return classLinker_.get();
173     }
174 
GetEtsClassLinkerExtension()175     EtsClassLinkerExtension *GetEtsClassLinkerExtension() const
176     {
177         return classLinker_.get()->GetEtsClassLinkerExtension();
178     }
179 
GetGlobalObjectStorage()180     mem::GlobalObjectStorage *GetGlobalObjectStorage() const override
181     {
182         ASSERT(mm_ != nullptr);
183         return mm_->GetGlobalObjectStorage();
184     }
185 
186     void DeleteGlobalRef(ets_object globalRef);
187 
188     void DeleteWeakGlobalRef(ets_weak weakRef);
189 
GetReferenceProcessor()190     mem::ReferenceProcessor *GetReferenceProcessor() const override
191     {
192         ASSERT(referenceProcessor_ != nullptr);
193         return referenceProcessor_;
194     }
195 
GetStringTable()196     StringTable *GetStringTable() const override
197     {
198         return stringTable_;
199     }
200 
GetMonitorPool()201     MonitorPool *GetMonitorPool() const override
202     {
203         return monitorPool_;
204     }
205 
GetAssociatedThread()206     ManagedThread *GetAssociatedThread() const override
207     {
208         return ManagedThread::GetCurrent();
209     }
210 
GetThreadManager()211     ThreadManager *GetThreadManager() const override
212     {
213         return coroutineManager_;
214     }
215 
GetCoroutineManager()216     CoroutineManager *GetCoroutineManager() const
217     {
218         return static_cast<CoroutineManager *>(GetThreadManager());
219     }
220 
GetRendezvous()221     Rendezvous *GetRendezvous() const override
222     {
223         return rendezvous_;
224     }
225 
GetCompiler()226     CompilerInterface *GetCompiler() const override
227     {
228         return compiler_;
229     }
230 
231     PANDA_PUBLIC_API ObjectHeader *GetOOMErrorObject() override;
232 
233     PANDA_PUBLIC_API ObjectHeader *GetUndefinedObject();
234 
GetCompilerRuntimeInterface()235     compiler::RuntimeInterface *GetCompilerRuntimeInterface() const override
236     {
237         return runtimeIface_;
238     }
239 
240     bool LoadNativeLibrary(EtsEnv *env, const PandaString &name);
241 
242     void ResolveNativeMethod(Method *method);
243 
FromEtsVM(EtsVM * vm)244     static PandaEtsVM *FromEtsVM(EtsVM *vm)
245     {
246         return static_cast<PandaEtsVM *>(vm);
247     }
248 
249     void RegisterFinalizationRegistryInstance(EtsObject *instance);
250 
251     [[noreturn]] static void Abort(const char *message = nullptr);
252 
GetExternalData()253     void *GetExternalData()
254     {
255         return externalData_.data;
256     }
257 
FromExternalData(void * externalData)258     static PandaEtsVM *FromExternalData(void *externalData)
259     {
260         ASSERT(externalData != nullptr);
261         return reinterpret_cast<PandaEtsVM *>(ToUintPtr(externalData) - MEMBER_OFFSET(PandaEtsVM, externalData_));
262     }
263 
264     struct alignas(16U) ExternalData {  // NOLINT(readability-magic-numbers)
265         static constexpr size_t SIZE = 256U * 3;
266         uint8_t data[SIZE];  // NOLINT(modernize-avoid-c-arrays)
267     };
268 
GetJobQueue()269     JobQueue *GetJobQueue() const
270     {
271         return jobQueue_.get();
272     }
273 
InitJobQueue(JobQueue * jobQueue)274     void InitJobQueue(JobQueue *jobQueue)
275     {
276         ASSERT(jobQueue_ == nullptr);
277         jobQueue_.reset(jobQueue);
278     }
279 
GetRandomEngine()280     std::mt19937 &GetRandomEngine()
281     {
282         ASSERT(randomEngine_);
283         return *randomEngine_;
284     }
285 
IsStaticProfileEnabled()286     bool IsStaticProfileEnabled() const override
287     {
288         return true;
289     }
290 
SetClearInteropHandleScopesFunction(const std::function<void (Frame *)> & func)291     void SetClearInteropHandleScopesFunction(const std::function<void(Frame *)> &func)
292     {
293         clearInteropHandleScopes_ = func;
294     }
295 
ClearInteropHandleScopes(Frame * frame)296     void ClearInteropHandleScopes(Frame *frame) override
297     {
298         if (clearInteropHandleScopes_) {
299             clearInteropHandleScopes_(frame);
300         }
301     }
302 
SetDestroyExternalDataFunction(const std::function<void (void *)> & func)303     void SetDestroyExternalDataFunction(const std::function<void(void *)> &func)
304     {
305         ASSERT(!destroyExternalData_);
306         destroyExternalData_ = func;
307     }
308 
GetAtomicsMutex()309     os::memory::Mutex &GetAtomicsMutex()
310     {
311         return atomicsMutex_;
312     }
313 
SupportGCSinglePassCompaction()314     bool SupportGCSinglePassCompaction() const override
315     {
316         return true;
317     }
318 
GetDoubleToStringCache()319     DoubleToStringCache *GetDoubleToStringCache()
320     {
321         return doubleToStringCache_;
322     }
323 
GetFloatToStringCache()324     FloatToStringCache *GetFloatToStringCache()
325     {
326         return floatToStringCache_;
327     }
328 
GetLongToStringCache()329     LongToStringCache *GetLongToStringCache()
330     {
331         return longToStringCache_;
332     }
333 
GetDoubleToStringCacheOffset()334     static constexpr uint32_t GetDoubleToStringCacheOffset()
335     {
336         return MEMBER_OFFSET(PandaEtsVM, doubleToStringCache_);
337     }
338 
339     void RegisterFinalizerForObject(EtsCoroutine *coro, const EtsHandle<EtsObject> &object, void (*finalizer)(void *),
340                                     void *finalizerArg);
341 
342     void CleanFinalizableReferenceList();
343 
344     void BeforeShutdown() override;
345 
346     /**
347      * @brief Method creates CallbackPosterFactory with your implementation. Here we use template to avoid
348      * usage of InternalAllocator outside the virtual machine.
349      */
350     template <class FactoryImpl, class... Args>
CreateCallbackPosterFactory(Args...args)351     void CreateCallbackPosterFactory(Args... args)
352     {
353         static_assert(std::is_base_of_v<CallbackPosterFactoryIface, FactoryImpl>);
354         static_assert(std::is_constructible_v<FactoryImpl, Args...>);
355         ASSERT(callbackPosterFactory_ == nullptr);
356         callbackPosterFactory_ = MakePandaUnique<FactoryImpl>(args...);
357     }
358 
359     /// @brief Uses CallbackPosterFactory to create a CallbackPoster
CreateCallbackPoster()360     PandaUniquePtr<CallbackPoster> CreateCallbackPoster()
361     {
362         auto *coro = EtsCoroutine::GetCurrent();
363         if (coro != coro->GetPandaVM()->GetCoroutineManager()->GetMainThread()) {
364             return nullptr;
365         }
366         ASSERT(callbackPosterFactory_ != nullptr);
367         return callbackPosterFactory_->CreatePoster();
368     }
369 
370 protected:
371     bool CheckEntrypointSignature(Method *entrypoint) override;
372     Expected<int, Runtime::Error> InvokeEntrypointImpl(Method *entrypoint,
373                                                        const std::vector<std::string> &args) override;
374     void HandleUncaughtException() override;
375 
376 private:
377     /**
378      * @brief Update a VM root that has been moved by GC.
379      * @param ref a reference to update, should hold an ObjectHeader pointer
380      * @tparam REF_CAN_BE_NULL true iff it is legal for @param ref to hold a null pointer
381      */
382     template <bool REF_CAN_BE_NULL>
383     static void UpdateMovedVmRef(Value &ref);
384 
385     static void UpdateManagedEntrypointArgRefs(EtsCoroutine *coroutine);
386 
InitializeRandomEngine()387     void InitializeRandomEngine()
388     {
389         ASSERT(!randomEngine_);
390         std::random_device rd;
391         randomEngine_.emplace(rd());
392     }
393 
394     explicit PandaEtsVM(Runtime *runtime, const RuntimeOptions &options, mem::MemoryManager *mm);
395 
396     Runtime *runtime_ {nullptr};
397     mem::MemoryManager *mm_ {nullptr};
398     PandaUniquePtr<EtsClassLinker> classLinker_;
399     mem::ReferenceProcessor *referenceProcessor_ {nullptr};
400     PandaVector<ObjectHeader *> gcRoots_;
401     Rendezvous *rendezvous_ {nullptr};
402     CompilerInterface *compiler_ {nullptr};
403     StringTable *stringTable_ {nullptr};
404     MonitorPool *monitorPool_ {nullptr};
405     CoroutineManager *coroutineManager_ {nullptr};
406     mem::Reference *oomObjRef_ {nullptr};
407     compiler::RuntimeInterface *runtimeIface_ {nullptr};
408     mem::Reference *undefinedObjRef_ {nullptr};
409     mem::Reference *finalizableWeakRefList_ {nullptr};
410     os::memory::Mutex finalizableWeakRefListLock_;
411     NativeLibraryProvider nativeLibraryProvider_;
412     os::memory::Mutex finalizationRegistryLock_;
413     PandaList<EtsObject *> registeredFinalizationRegistryInstances_ GUARDED_BY(finalizationRegistryLock_);
414     PandaUniquePtr<JobQueue> jobQueue_;
415     PandaUniquePtr<CallbackPosterFactoryIface> callbackPosterFactory_;
416     // optional for lazy initialization
417     std::optional<std::mt19937> randomEngine_;
418     std::function<void(Frame *)> clearInteropHandleScopes_;
419     std::function<void(void *)> destroyExternalData_;
420     // for JS Atomics
421     os::memory::Mutex atomicsMutex_;
422     DoubleToStringCache *doubleToStringCache_ {nullptr};
423     FloatToStringCache *floatToStringCache_ {nullptr};
424     LongToStringCache *longToStringCache_ {nullptr};
425 
426     ExternalData externalData_ {};
427 
428     NO_MOVE_SEMANTIC(PandaEtsVM);
429     NO_COPY_SEMANTIC(PandaEtsVM);
430 
431     friend class mem::Allocator;
432 };
433 
434 }  // namespace ark::ets
435 
436 #endif  // !PANDA_PLUGINS_ETS_RUNTIME_ETS_VM_H_
437