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/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 #include "plugins/ets/runtime/ets_taskpool.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 GetTaskpool()274 Taskpool *GetTaskpool() 275 { 276 return taskpool_; 277 } 278 GetTaskpool()279 const Taskpool *GetTaskpool() const 280 { 281 return taskpool_; 282 } 283 InitJobQueue(JobQueue * jobQueue)284 void InitJobQueue(JobQueue *jobQueue) 285 { 286 ASSERT(jobQueue_ == nullptr); 287 jobQueue_.reset(jobQueue); 288 Coroutine::GetCurrent()->SetCallbackQueue(jobQueue); 289 } 290 GetRandomEngine()291 std::mt19937 &GetRandomEngine() 292 { 293 ASSERT(randomEngine_); 294 return *randomEngine_; 295 } 296 IsStaticProfileEnabled()297 bool IsStaticProfileEnabled() const override 298 { 299 return true; 300 } 301 SetClearInteropHandleScopesFunction(const std::function<void (Frame *)> & func)302 void SetClearInteropHandleScopesFunction(const std::function<void(Frame *)> &func) 303 { 304 clearInteropHandleScopes_ = func; 305 } 306 ClearInteropHandleScopes(Frame * frame)307 void ClearInteropHandleScopes(Frame *frame) override 308 { 309 if (clearInteropHandleScopes_) { 310 clearInteropHandleScopes_(frame); 311 } 312 } 313 SetDestroyExternalDataFunction(const std::function<void (void *)> & func)314 void SetDestroyExternalDataFunction(const std::function<void(void *)> &func) 315 { 316 ASSERT(!destroyExternalData_); 317 destroyExternalData_ = func; 318 } 319 GetAtomicsMutex()320 os::memory::Mutex &GetAtomicsMutex() 321 { 322 return atomicsMutex_; 323 } 324 SupportGCSinglePassCompaction()325 bool SupportGCSinglePassCompaction() const override 326 { 327 return true; 328 } 329 GetDoubleToStringCache()330 DoubleToStringCache *GetDoubleToStringCache() 331 { 332 return doubleToStringCache_; 333 } 334 GetFloatToStringCache()335 FloatToStringCache *GetFloatToStringCache() 336 { 337 return floatToStringCache_; 338 } 339 GetLongToStringCache()340 LongToStringCache *GetLongToStringCache() 341 { 342 return longToStringCache_; 343 } 344 GetDoubleToStringCacheOffset()345 static constexpr uint32_t GetDoubleToStringCacheOffset() 346 { 347 return MEMBER_OFFSET(PandaEtsVM, doubleToStringCache_); 348 } 349 350 void RegisterFinalizerForObject(EtsCoroutine *coro, const EtsHandle<EtsObject> &object, void (*finalizer)(void *), 351 void *finalizerArg); 352 353 void UnlinkFinalizableReference(EtsCoroutine *coro, EtsFinalizableWeakRef *weakRef); 354 355 void CleanFinalizableReferenceList(); 356 357 protected: 358 bool CheckEntrypointSignature(Method *entrypoint) override; 359 Expected<int, Runtime::Error> InvokeEntrypointImpl(Method *entrypoint, 360 const std::vector<std::string> &args) override; 361 void HandleUncaughtException() override; 362 363 private: 364 /** 365 * @brief Update a VM root that has been moved by GC. 366 * @param ref a reference to update, should hold an ObjectHeader pointer 367 * @tparam REF_CAN_BE_NULL true iff it is legal for @param ref to hold a null pointer 368 */ 369 template <bool REF_CAN_BE_NULL> 370 static void UpdateMovedVmRef(Value &ref); 371 InitializeRandomEngine()372 void InitializeRandomEngine() 373 { 374 ASSERT(!randomEngine_); 375 std::random_device rd; 376 randomEngine_.emplace(rd()); 377 } 378 379 explicit PandaEtsVM(Runtime *runtime, const RuntimeOptions &options, mem::MemoryManager *mm); 380 381 Runtime *runtime_ {nullptr}; 382 mem::MemoryManager *mm_ {nullptr}; 383 PandaUniquePtr<EtsClassLinker> classLinker_; 384 mem::ReferenceProcessor *referenceProcessor_ {nullptr}; 385 PandaVector<ObjectHeader *> gcRoots_; 386 Rendezvous *rendezvous_ {nullptr}; 387 CompilerInterface *compiler_ {nullptr}; 388 StringTable *stringTable_ {nullptr}; 389 MonitorPool *monitorPool_ {nullptr}; 390 CoroutineManager *coroutineManager_ {nullptr}; 391 mem::Reference *oomObjRef_ {nullptr}; 392 compiler::RuntimeInterface *runtimeIface_ {nullptr}; 393 mem::Reference *undefinedObjRef_ {nullptr}; 394 mem::Reference *finalizableWeakRefList_ {nullptr}; 395 os::memory::Mutex finalizableWeakRefListLock_; 396 NativeLibraryProvider nativeLibraryProvider_; 397 os::memory::Mutex finalizationRegistryLock_; 398 PandaList<EtsObject *> registeredFinalizationRegistryInstances_ GUARDED_BY(finalizationRegistryLock_); 399 PandaUniquePtr<JobQueue> jobQueue_; 400 Taskpool *taskpool_ {nullptr}; 401 // optional for lazy initialization 402 std::optional<std::mt19937> randomEngine_; 403 std::function<void(Frame *)> clearInteropHandleScopes_; 404 std::function<void(void *)> destroyExternalData_; 405 // for JS Atomics 406 os::memory::Mutex atomicsMutex_; 407 DoubleToStringCache *doubleToStringCache_ {nullptr}; 408 FloatToStringCache *floatToStringCache_ {nullptr}; 409 LongToStringCache *longToStringCache_ {nullptr}; 410 411 ExternalData externalData_ {}; 412 413 NO_MOVE_SEMANTIC(PandaEtsVM); 414 NO_COPY_SEMANTIC(PandaEtsVM); 415 416 friend class mem::Allocator; 417 }; 418 419 } // namespace ark::ets 420 421 #endif // !PANDA_PLUGINS_ETS_RUNTIME_ETS_VM_H_ 422