• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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