• 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 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/gc_task.h"
33 #include "runtime/include/language_context.h"
34 #include "runtime/include/managed_thread.h"
35 #include "runtime/include/mem/panda_containers.h"
36 #include "runtime/include/mem/panda_string.h"
37 #include "runtime/include/method.h"
38 #include "runtime/include/object_header.h"
39 #include "runtime/include/panda_vm.h"
40 #include "runtime/include/runtime_options.h"
41 #include "runtime/include/runtime.h"
42 #include "runtime/mem/gc/gc_stats.h"
43 #include "runtime/mem/gc/gc_trigger.h"
44 #include "runtime/mem/gc/gc.h"
45 #include "runtime/mem/gc/reference-processor/reference_processor.h"
46 #include "runtime/mem/heap_manager.h"
47 #include "runtime/mem/memory_manager.h"
48 #include "runtime/mem/refstorage/global_object_storage.h"
49 #include "runtime/mem/rendezvous.h"
50 #include "runtime/monitor_pool.h"
51 #include "runtime/string_table.h"
52 #include "runtime/thread_manager.h"
53 #include "plugins/ets/runtime/ets_class_linker.h"
54 #include "plugins/ets/runtime/ets_coroutine.h"
55 #include "runtime/coroutines/coroutine_manager.h"
56 #include "plugins/ets/runtime/ets_native_library_provider.h"
57 #include "plugins/ets/runtime/napi/ets_napi.h"
58 #include "plugins/ets/runtime/types/ets_object.h"
59 #include "plugins/ets/runtime/job_queue.h"
60 #include "plugins/ets/runtime/ets_handle_scope.h"
61 #include "plugins/ets/runtime/ets_handle.h"
62 
63 namespace panda::ets {
64 
65 class PromiseListener {
66 public:
67     PromiseListener() = default;
68     virtual ~PromiseListener() = default;
69 
70     virtual void OnPromiseStateChanged(EtsHandle<EtsPromise> &) = 0;
71 
72     DEFAULT_COPY_SEMANTIC(PromiseListener);
73     DEFAULT_MOVE_SEMANTIC(PromiseListener);
74 };
75 
76 class PandaEtsVM final : public PandaVM, public EtsVM {  // NOLINT(fuchsia-multiple-inheritance)
77 public:
78     static Expected<PandaEtsVM *, PandaString> Create(Runtime *runtime, const RuntimeOptions &options);
79     static bool Destroy(PandaEtsVM *vm);
80 
81     ~PandaEtsVM() override;
82 
83     PANDA_PUBLIC_API static PandaEtsVM *GetCurrent();
84 
85     /**
86      * @brief Create TaskManager if needed and set it to runtime
87      * @note It's temporary solution, TaskManager will be created outside VM in the future
88      *
89      * @param options runtime options
90      *
91      * @return true if TaskManager was created, false - otherwise
92      */
93     static bool CreateTaskManagerIfNeeded(const RuntimeOptions &options);
94 
95     bool Initialize() override;
96     bool InitializeFinish() override;
97 
98     void PreStartup() override;
99     void PreZygoteFork() override;
100     void PostZygoteFork() override;
101     void InitializeGC() override;
102     void StartGC() override;
103     void StopGC() override;
104     void SweepVmRefs(const GCObjectVisitor &gcObjectVisitor) override;
105     void VisitVmRoots(const GCRootVisitor &visitor) override;
106     void UpdateVmRefs() override;
107     void UninitializeThreads() override;
108 
109     void HandleReferences(const GCTask &task, const mem::GC::ReferenceClearPredicateT &pred) override;
110     void HandleGCRoutineInMutator() override;
111     void HandleGCFinished() override;
112 
GetOptions()113     const RuntimeOptions &GetOptions() const override
114     {
115         return Runtime::GetOptions();
116     }
117 
GetLanguageContext()118     LanguageContext GetLanguageContext() const override
119     {
120         return Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS);
121     }
122 
ResolveString(const panda_file::File & pf,panda_file::File::EntityId id)123     coretypes::String *ResolveString(const panda_file::File &pf, panda_file::File::EntityId id) override
124     {
125         coretypes::String *str = GetStringTable()->GetInternalStringFast(pf, id);
126         if (str != nullptr) {
127             return str;
128         }
129         str = GetStringTable()->GetOrInternInternalString(pf, id, GetLanguageContext());
130         return str;
131     }
132 
ResolveString(Frame * frame,panda_file::File::EntityId id)133     coretypes::String *ResolveString(Frame *frame, panda_file::File::EntityId id) override
134     {
135         return PandaEtsVM::ResolveString(*frame->GetMethod()->GetPandaFile(), id);
136     }
137 
138     coretypes::String *CreateString(Method *ctor, ObjectHeader *obj) override;
139 
GetRuntime()140     Runtime *GetRuntime() const
141     {
142         return runtime_;
143     }
144 
GetHeapManager()145     mem::HeapManager *GetHeapManager() const override
146     {
147         ASSERT(mm_ != nullptr);
148         return mm_->GetHeapManager();
149     }
150 
GetMemStats()151     mem::MemStatsType *GetMemStats() const override
152     {
153         ASSERT(mm_ != nullptr);
154         return mm_->GetMemStats();
155     }
156 
GetGC()157     mem::GC *GetGC() const override
158     {
159         ASSERT(mm_ != nullptr);
160         return mm_->GetGC();
161     }
162 
GetGCTrigger()163     mem::GCTrigger *GetGCTrigger() const override
164     {
165         ASSERT(mm_ != nullptr);
166         return mm_->GetGCTrigger();
167     }
168 
GetGCStats()169     mem::GCStats *GetGCStats() const override
170     {
171         ASSERT(mm_ != nullptr);
172         return mm_->GetGCStats();
173     }
174 
GetClassLinker()175     EtsClassLinker *GetClassLinker() const
176     {
177         return classLinker_.get();
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 RegisterFinalizationQueueInstance(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 = 512U;
266         uint8_t data[SIZE];  // NOLINT(modernize-avoid-c-arrays)
267     };
268 
GetJobQueue()269     JobQueue *GetJobQueue()
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 
280     PANDA_PUBLIC_API void AddPromiseListener(EtsPromise *promise, PandaUniquePtr<PromiseListener> &&listener);
281 
282     void FirePromiseStateChanged(EtsHandle<EtsPromise> &promise);
283 
GetRandomEngine()284     std::mt19937 &GetRandomEngine()
285     {
286         ASSERT(randomEngine_);
287         return *randomEngine_;
288     }
289 
IsStaticProfileEnabled()290     bool IsStaticProfileEnabled() const override
291     {
292         return true;
293     }
294 
SetClearInteropHandleScopesFunction(const std::function<void (Frame *)> & func)295     void SetClearInteropHandleScopesFunction(const std::function<void(Frame *)> &func)
296     {
297         clearInteropHandleScopes_ = func;
298     }
299 
ClearInteropHandleScopes(Frame * frame)300     void ClearInteropHandleScopes(Frame *frame) override
301     {
302         if (clearInteropHandleScopes_) {
303             clearInteropHandleScopes_(frame);
304         }
305     }
306 
GetAtomicsMutex()307     os::memory::Mutex &GetAtomicsMutex()
308     {
309         return atomicsMutex_;
310     }
311 
312 protected:
313     bool CheckEntrypointSignature(Method *entrypoint) override;
314     Expected<int, Runtime::Error> InvokeEntrypointImpl(Method *entrypoint,
315                                                        const std::vector<std::string> &args) override;
316     void HandleUncaughtException() override;
317 
318 private:
319     /**
320      * @brief Update a VM root that has been moved by GC.
321      * @param ref a reference to update, should hold an ObjectHeader pointer
322      * @tparam REF_CAN_BE_NULL true iff it is legal for @param ref to hold a null pointer
323      */
324     template <bool REF_CAN_BE_NULL>
325     static void UpdateMovedVmRef(Value &ref);
326 
InitializeRandomEngine()327     void InitializeRandomEngine()
328     {
329         ASSERT(!randomEngine_);
330         std::random_device rd;
331         randomEngine_.emplace(rd());
332     }
333 
334     class PromiseListenerInfo {
335     public:
PromiseListenerInfo(EtsPromise * promise,PandaUniquePtr<PromiseListener> && listener)336         PromiseListenerInfo(EtsPromise *promise, PandaUniquePtr<PromiseListener> &&listener)
337             : promise_(promise), listener_(std::move(listener))
338         {
339         }
340 
GetPromise()341         EtsPromise *GetPromise() const
342         {
343             return promise_;
344         }
345 
346         void UpdateRefToMovedObject();
347         void OnPromiseStateChanged(EtsHandle<EtsPromise> &promise);
348 
349     private:
350         EtsPromise *promise_;
351         PandaUniquePtr<PromiseListener> listener_;
352     };
353 
354     explicit PandaEtsVM(Runtime *runtime, const RuntimeOptions &options, mem::MemoryManager *mm);
355 
356     Runtime *runtime_ {nullptr};
357     mem::MemoryManager *mm_ {nullptr};
358     PandaUniquePtr<EtsClassLinker> classLinker_;
359     mem::ReferenceProcessor *referenceProcessor_ {nullptr};
360     PandaVector<ObjectHeader *> gcRoots_;
361     Rendezvous *rendezvous_ {nullptr};
362     CompilerInterface *compiler_ {nullptr};
363     StringTable *stringTable_ {nullptr};
364     MonitorPool *monitorPool_ {nullptr};
365     CoroutineManager *coroutineManager_ {nullptr};
366     mem::Reference *oomObjRef_ {nullptr};
367     compiler::RuntimeInterface *runtimeIface_ {nullptr};
368     mem::Reference *undefinedObjRef_ {nullptr};
369     NativeLibraryProvider nativeLibraryProvider_;
370     os::memory::Mutex finalizationQueueLock_;
371     PandaList<EtsObject *> registeredFinalizationQueueInstances_ GUARDED_BY(finalizationQueueLock_);
372     PandaUniquePtr<JobQueue> jobQueue_;
373     os::memory::Mutex promiseListenersLock_;
374     // NOTE(audovichenko) Should be refactored #12030
375     PandaList<PromiseListenerInfo> promiseListeners_ GUARDED_BY(promiseListenersLock_);
376     // optional for lazy initialization
377     std::optional<std::mt19937> randomEngine_;
378     std::function<void(Frame *)> clearInteropHandleScopes_;
379     // for JS Atomics
380     os::memory::Mutex atomicsMutex_;
381 
382     ExternalData externalData_ {};
383 
384     NO_MOVE_SEMANTIC(PandaEtsVM);
385     NO_COPY_SEMANTIC(PandaEtsVM);
386 
387     friend class mem::Allocator;
388 };
389 
390 }  // namespace panda::ets
391 
392 #endif  // !PANDA_PLUGINS_ETS_RUNTIME_ETS_VM_H
393