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