1 /** 2 * Copyright (c) 2022-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 #ifndef PANDA_PLUGINS_ETS_RUNTIME_ETS_COROUTINE_H 16 #define PANDA_PLUGINS_ETS_RUNTIME_ETS_COROUTINE_H 17 18 #include "runtime/coroutines/coroutine_context.h" 19 #include "plugins/ets/runtime/ets_napi_env.h" 20 #include "plugins/ets/runtime/external_iface_table.h" 21 #include "runtime/coroutines/coroutine.h" 22 #include "runtime/coroutines/coroutine_manager.h" 23 #include "runtime/coroutines/local_storage.h" 24 #include "runtime/include/panda_vm.h" 25 26 namespace ark::ets { 27 class PandaEtsVM; 28 29 /// @brief The eTS coroutine. It is aware of the native interface and reference storage existance. 30 class EtsCoroutine : public Coroutine { 31 public: 32 NO_COPY_SEMANTIC(EtsCoroutine); 33 NO_MOVE_SEMANTIC(EtsCoroutine); 34 35 enum class DataIdx { ETS_PLATFORM_TYPES_PTR, INTEROP_CTX_PTR, LAST_ID }; 36 using LocalStorage = StaticLocalStorage<DataIdx>; 37 38 /** 39 * @brief EtsCoroutine factory: the preferrable way to create a coroutine. See CoroutineManager::CoroutineFactory 40 * for details. 41 * 42 * Since C++ requires function type to exactly match the formal parameter type, we have to make this factory a 43 * template. The sole purpose for this is to be able to return both Coroutine* and EtsCoroutine* 44 */ 45 template <class T> 46 static T *Create(Runtime *runtime, PandaVM *vm, PandaString name, CoroutineContext *context, 47 std::optional<EntrypointInfo> &&epInfo = std::nullopt, Type type = Type::MUTATOR, 48 CoroutinePriority priority = CoroutinePriority::MEDIUM_PRIORITY) 49 { 50 mem::InternalAllocatorPtr allocator = runtime->GetInternalAllocator(); 51 auto co = allocator->New<EtsCoroutine>(os::thread::GetCurrentThreadId(), allocator, vm, std::move(name), 52 context, std::move(epInfo), type, priority); 53 ASSERT(co != nullptr); 54 co->Initialize(); 55 return co; 56 } 57 ~EtsCoroutine()58 ~EtsCoroutine() override 59 { 60 auto allocator = GetVM()->GetHeapManager()->GetInternalAllocator(); 61 allocator->Delete(etsNapiEnv_); 62 } 63 CastFromThread(Thread * thread)64 static EtsCoroutine *CastFromThread(Thread *thread) 65 { 66 ASSERT(thread != nullptr); 67 return static_cast<EtsCoroutine *>(thread); 68 } 69 GetCurrent()70 static EtsCoroutine *GetCurrent() 71 { 72 Coroutine *co = Coroutine::GetCurrent(); 73 if ((co != nullptr) && co->GetThreadLang() == ark::panda_file::SourceLang::ETS) { 74 return CastFromThread(co); 75 } 76 return nullptr; 77 } 78 79 ExternalIfaceTable *GetExternalIfaceTable(); 80 SetPromiseClass(void * promiseClass)81 void SetPromiseClass(void *promiseClass) 82 { 83 promiseClassPtr_ = promiseClass; 84 } 85 SetJobClass(void * jobClass)86 void SetJobClass(void *jobClass) 87 { 88 jobClassPtr_ = jobClass; 89 } 90 GetTlsPromiseClassPointerOffset()91 static constexpr uint32_t GetTlsPromiseClassPointerOffset() 92 { 93 return MEMBER_OFFSET(EtsCoroutine, promiseClassPtr_); 94 } 95 96 // Returns a unique object representing "null" reference GetNullValue()97 ALWAYS_INLINE ObjectHeader *GetNullValue() const 98 { 99 return nullValue_; 100 } 101 102 // For mainthread initializer SetupNullValue(ObjectHeader * obj)103 void SetupNullValue(ObjectHeader *obj) 104 { 105 nullValue_ = obj; 106 } 107 GetTlsNullValueOffset()108 static constexpr uint32_t GetTlsNullValueOffset() 109 { 110 return MEMBER_OFFSET(EtsCoroutine, nullValue_); 111 } 112 GetTlsNapiEnvOffset()113 static constexpr uint32_t GetTlsNapiEnvOffset() 114 { 115 return MEMBER_OFFSET(EtsCoroutine, etsNapiEnv_); 116 } 117 118 PANDA_PUBLIC_API PandaEtsVM *GetPandaVM() const; 119 PANDA_PUBLIC_API CoroutineManager *GetCoroutineManager() const; 120 GetEtsNapiEnv()121 PandaEtsNapiEnv *GetEtsNapiEnv() const 122 { 123 return etsNapiEnv_; 124 } 125 126 void Initialize() override; 127 void CleanUp() override; 128 void RequestCompletion(Value returnValue) override; 129 void FreeInternalMemory() override; 130 131 void ListUnhandledEventsOnProgramExit() override; 132 GetLocalStorage()133 LocalStorage &GetLocalStorage() 134 { 135 return localStorage_; 136 } 137 138 // event handlers 139 void OnHostWorkerChanged() override; 140 141 /// @brief print stack and exit the program 142 [[noreturn]] void HandleUncaughtException() override; 143 144 static constexpr CoroutinePriority ASYNC_CALL = CoroutinePriority::HIGH_PRIORITY; 145 static constexpr CoroutinePriority PROMISE_CALLBACK = CoroutinePriority::HIGH_PRIORITY; 146 static constexpr CoroutinePriority TIMER_CALLBACK = CoroutinePriority::MEDIUM_PRIORITY; 147 static constexpr CoroutinePriority LAUNCH = CoroutinePriority::MEDIUM_PRIORITY; 148 149 protected: 150 // we would like everyone to use the factory to create a EtsCoroutine 151 explicit EtsCoroutine(ThreadId id, mem::InternalAllocatorPtr allocator, PandaVM *vm, PandaString name, 152 CoroutineContext *context, std::optional<EntrypointInfo> &&epInfo, Type type, 153 CoroutinePriority priority); 154 155 private: 156 panda_file::Type GetReturnType(); 157 EtsObject *GetReturnValueAsObject(panda_file::Type returnType, Value returnValue); 158 EtsObject *GetValueFromPromiseSync(EtsPromise *promise); 159 160 void RequestPromiseCompletion(mem::Reference *promiseRef, Value returnValue); 161 void RequestJobCompletion(mem::Reference *jobRef, Value returnValue); 162 163 void ListUnhandledJobs(); 164 void ListUnhandledPromises(); 165 166 PandaEtsNapiEnv *etsNapiEnv_ {nullptr}; 167 void *promiseClassPtr_ {nullptr}; 168 void *jobClassPtr_ {nullptr}; 169 170 ObjectHeader *nullValue_ {}; 171 172 static ExternalIfaceTable emptyExternalIfaceTable_; 173 174 LocalStorage localStorage_; 175 176 static_assert(std::is_pointer_v<decltype(etsNapiEnv_)>, 177 "we load a raw pointer in compiled code, please don't change the type!"); 178 179 // Allocator calls our protected ctor 180 friend class mem::Allocator; 181 }; 182 } // namespace ark::ets 183 184 #endif // PANDA_PLUGINS_ETS_RUNTIME_ETS_COROUTINE_H 185