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