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