• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2023-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_RUNTIME_ETS_FFI_CLASSES_ETS_PROMISE_H_
17 #define PANDA_RUNTIME_ETS_FFI_CLASSES_ETS_PROMISE_H_
18 
19 #include "libpandabase/macros.h"
20 #include "plugins/ets/runtime/ets_panda_file_items.h"
21 #include "plugins/ets/runtime/types/ets_object.h"
22 #include "plugins/ets/runtime/types/ets_array.h"
23 #include "plugins/ets/runtime/types/ets_sync_primitives.h"
24 #include "plugins/ets/runtime/types/ets_primitives.h"
25 #include "runtime/coroutines/coroutine_events.h"
26 #include "plugins/ets/runtime/ets_remote_promise_resolver.h"
27 
28 namespace ark::ets {
29 
30 class EtsCoroutine;
31 
32 namespace test {
33 class EtsPromiseTest;
34 }  // namespace test
35 
36 class EtsPromise : public ObjectHeader {
37 public:
38     // temp
39     static constexpr EtsInt STATE_PENDING = 0;
40     static constexpr EtsInt STATE_RESOLVED = 1;
41     static constexpr EtsInt STATE_REJECTED = 2;
42 
43     EtsPromise() = delete;
44     ~EtsPromise() = delete;
45 
46     NO_COPY_SEMANTIC(EtsPromise);
47     NO_MOVE_SEMANTIC(EtsPromise);
48 
49     PANDA_PUBLIC_API static EtsPromise *Create(EtsCoroutine *etsCoroutine = EtsCoroutine::GetCurrent());
50 
FromCoreType(ObjectHeader * promise)51     static EtsPromise *FromCoreType(ObjectHeader *promise)
52     {
53         return reinterpret_cast<EtsPromise *>(promise);
54     }
55 
GetCoreType()56     ObjectHeader *GetCoreType() const
57     {
58         return static_cast<ObjectHeader *>(const_cast<EtsPromise *>(this));
59     }
60 
AsObject()61     EtsObject *AsObject()
62     {
63         return EtsObject::FromCoreType(this);
64     }
65 
AsObject()66     const EtsObject *AsObject() const
67     {
68         return EtsObject::FromCoreType(this);
69     }
70 
FromEtsObject(EtsObject * promise)71     static EtsPromise *FromEtsObject(EtsObject *promise)
72     {
73         return reinterpret_cast<EtsPromise *>(promise);
74     }
75 
GetCallbackQueue(EtsCoroutine * coro)76     EtsObjectArray *GetCallbackQueue(EtsCoroutine *coro)
77     {
78         return EtsObjectArray::FromCoreType(
79             ObjectAccessor::GetObject(coro, this, MEMBER_OFFSET(EtsPromise, callbackQueue_)));
80     }
81 
SetCallbackQueue(EtsCoroutine * coro,EtsObjectArray * callbackQueue)82     void SetCallbackQueue(EtsCoroutine *coro, EtsObjectArray *callbackQueue)
83     {
84         ObjectAccessor::SetObject(coro, this, MEMBER_OFFSET(EtsPromise, callbackQueue_), callbackQueue->GetCoreType());
85     }
86 
GetLaunchModeQueue(EtsCoroutine * coro)87     EtsIntArray *GetLaunchModeQueue(EtsCoroutine *coro)
88     {
89         return reinterpret_cast<EtsIntArray *>(
90             ObjectAccessor::GetObject(coro, this, MEMBER_OFFSET(EtsPromise, launchModeQueue_)));
91     }
92 
SetLaunchModeQueue(EtsCoroutine * coro,EtsIntArray * launchModeQueue)93     void SetLaunchModeQueue(EtsCoroutine *coro, EtsIntArray *launchModeQueue)
94     {
95         ObjectAccessor::SetObject(coro, this, MEMBER_OFFSET(EtsPromise, launchModeQueue_),
96                                   launchModeQueue->GetCoreType());
97     }
98 
GetQueueSize()99     EtsInt GetQueueSize()
100     {
101         return queueSize_;
102     }
103 
IsResolved()104     bool IsResolved() const
105     {
106         return (state_ == STATE_RESOLVED);
107     }
108 
IsRejected()109     bool IsRejected() const
110     {
111         return (state_ == STATE_REJECTED);
112     }
113 
IsPending()114     bool IsPending() const
115     {
116         return (state_ == STATE_PENDING);
117     }
118 
IsProxy()119     bool IsProxy()
120     {
121         return GetLinkedPromise(EtsCoroutine::GetCurrent()) != nullptr;
122     }
123 
GetInteropObject(EtsCoroutine * coro)124     EtsObject *GetInteropObject(EtsCoroutine *coro)
125     {
126         auto *obj = ObjectAccessor::GetObject(coro, this, MEMBER_OFFSET(EtsPromise, interopObject_));
127         return EtsObject::FromCoreType(obj);
128     }
129 
SetInteropObject(EtsCoroutine * coro,EtsObject * o)130     void SetInteropObject(EtsCoroutine *coro, EtsObject *o)
131     {
132         ObjectAccessor::SetObject(coro, this, MEMBER_OFFSET(EtsPromise, interopObject_), o->GetCoreType());
133     }
134 
GetLinkedPromise(EtsCoroutine * coro)135     EtsObject *GetLinkedPromise(EtsCoroutine *coro)
136     {
137         auto *obj = ObjectAccessor::GetObject(coro, this, MEMBER_OFFSET(EtsPromise, linkedPromise_));
138         return EtsObject::FromCoreType(obj);
139     }
140 
SetLinkedPromise(EtsCoroutine * coro,EtsObject * p)141     void SetLinkedPromise(EtsCoroutine *coro, EtsObject *p)
142     {
143         ObjectAccessor::SetObject(coro, this, MEMBER_OFFSET(EtsPromise, linkedPromise_), p->GetCoreType());
144     }
145 
GetMutex(EtsCoroutine * coro)146     EtsMutex *GetMutex(EtsCoroutine *coro)
147     {
148         auto *obj = ObjectAccessor::GetObject(coro, this, MEMBER_OFFSET(EtsPromise, mutex_));
149         return EtsMutex::FromCoreType(obj);
150     }
151 
SetMutex(EtsCoroutine * coro,EtsMutex * mutex)152     void SetMutex(EtsCoroutine *coro, EtsMutex *mutex)
153     {
154         ObjectAccessor::SetObject(coro, this, MEMBER_OFFSET(EtsPromise, mutex_), mutex->GetCoreType());
155     }
156 
GetEvent(EtsCoroutine * coro)157     EtsEvent *GetEvent(EtsCoroutine *coro)
158     {
159         auto *obj = ObjectAccessor::GetObject(coro, this, MEMBER_OFFSET(EtsPromise, event_));
160         return EtsEvent::FromCoreType(obj);
161     }
162 
SetEvent(EtsCoroutine * coro,EtsEvent * event)163     void SetEvent(EtsCoroutine *coro, EtsEvent *event)
164     {
165         ObjectAccessor::SetObject(coro, this, MEMBER_OFFSET(EtsPromise, event_), event->GetCoreType());
166     }
167 
Resolve(EtsCoroutine * coro,EtsObject * value)168     void Resolve(EtsCoroutine *coro, EtsObject *value)
169     {
170         ASSERT(state_ == STATE_PENDING);
171         auto coreValue = (value == nullptr) ? nullptr : value->GetCoreType();
172         ObjectAccessor::SetObject(coro, this, MEMBER_OFFSET(EtsPromise, value_), coreValue);
173         state_ = STATE_RESOLVED;
174         OnPromiseCompletion(coro);
175     }
176 
Reject(EtsCoroutine * coro,EtsObject * error)177     void Reject(EtsCoroutine *coro, EtsObject *error)
178     {
179         ASSERT(state_ == STATE_PENDING);
180         ObjectAccessor::SetObject(coro, this, MEMBER_OFFSET(EtsPromise, value_), error->GetCoreType());
181         state_ = STATE_REJECTED;
182         OnPromiseCompletion(coro);
183     }
184 
SubmitCallback(EtsCoroutine * coro,EtsObject * callback,CoroutineLaunchMode launchMode)185     void SubmitCallback(EtsCoroutine *coro, EtsObject *callback, CoroutineLaunchMode launchMode)
186     {
187         ASSERT(IsLocked());
188         ASSERT(queueSize_ < static_cast<int>(GetCallbackQueue(coro)->GetLength()));
189         auto *cbQueue = GetCallbackQueue(coro);
190         auto *launchModeQueue = GetLaunchModeQueue(coro);
191         launchModeQueue->Set(queueSize_, static_cast<int>(launchMode));
192         cbQueue->Set(queueSize_, callback);
193         queueSize_++;
194     }
195 
GetValue(EtsCoroutine * coro)196     EtsObject *GetValue(EtsCoroutine *coro)
197     {
198         return EtsObject::FromCoreType(ObjectAccessor::GetObject(coro, this, MEMBER_OFFSET(EtsPromise, value_)));
199     }
200 
GetState()201     uint32_t GetState() const
202     {
203         return state_;
204     }
205 
ValueOffset()206     static size_t ValueOffset()
207     {
208         return MEMBER_OFFSET(EtsPromise, value_);
209     }
210 
211     /// Allows to get exclusive access to the promise state
Lock()212     void Lock()
213     {
214         auto *mutex = GetMutex(EtsCoroutine::GetCurrent());
215         ASSERT(mutex != nullptr);
216         mutex->Lock();
217     }
218 
Unlock()219     void Unlock()
220     {
221         auto *mutex = GetMutex(EtsCoroutine::GetCurrent());
222         ASSERT(mutex != nullptr);
223         ASSERT(mutex->IsHeld());
224         mutex->Unlock();
225     }
226 
IsLocked()227     bool IsLocked()
228     {
229         auto *mutex = GetMutex(EtsCoroutine::GetCurrent());
230         ASSERT(mutex != nullptr);
231         return mutex->IsHeld();
232     }
233 
234     /// Blocks current coroutine until promise is resolved/rejected
Wait()235     void Wait()
236     {
237         auto *event = GetEvent(EtsCoroutine::GetCurrent());
238         ASSERT(event != nullptr);
239         event->Wait();
240     }
241 
242     // launch promise then/catch callback: void()
243     static void LaunchCallback(EtsCoroutine *coro, EtsObject *callback, CoroutineLaunchMode launchMode);
244 
SetEtsPromiseResolver(RemotePromiseResolver * resolver)245     void SetEtsPromiseResolver(RemotePromiseResolver *resolver)
246     {
247         remotePromiseResolver_ = reinterpret_cast<EtsLong>(resolver);
248     }
249 
250 private:
251     void OnPromiseCompletion(EtsCoroutine *coro);
252 
ClearQueues(EtsCoroutine * coro)253     void ClearQueues(EtsCoroutine *coro)
254     {
255         ObjectAccessor::SetObject(coro, this, MEMBER_OFFSET(EtsPromise, callbackQueue_), nullptr);
256         ObjectAccessor::SetObject(coro, this, MEMBER_OFFSET(EtsPromise, launchModeQueue_), nullptr);
257         queueSize_ = 0;
258     }
259 
GetPromiseResolver()260     RemotePromiseResolver *GetPromiseResolver() const
261     {
262         return reinterpret_cast<RemotePromiseResolver *>(remotePromiseResolver_);
263     }
264 
InvalidatePromiseResolver()265     void InvalidatePromiseResolver()
266     {
267         SetEtsPromiseResolver(nullptr);
268     }
269 
270     ObjectPointer<EtsObject> value_;  // the completion value of the Promise
271     ObjectPointer<EtsMutex> mutex_;
272     ObjectPointer<EtsEvent> event_;
273     ObjectPointer<EtsObjectArray>
274         callbackQueue_;  // the queue of 'then and catch' calbacks which will be called when the Promise gets fulfilled
275     ObjectPointer<EtsIntArray> launchModeQueue_;  // the queue of callbacks' launch mode
276     ObjectPointer<EtsObject> interopObject_;      // internal object used in js interop
277     ObjectPointer<EtsObject> linkedPromise_;      // linked JS promise as JSValue (if exists)
278     EtsInt queueSize_;
279     EtsLong remotePromiseResolver_;  // resolver for mirror promise
280     uint32_t state_;                 // the Promise's state
281 
282     friend class test::EtsPromiseTest;
283 };
284 
285 }  // namespace ark::ets
286 
287 #endif  // PANDA_RUNTIME_ETS_FFI_CLASSES_ETS_PROMISE_H_
288