• 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 #include "runtime/coroutines/coroutine_events.h"
17 #include "plugins/ets/runtime/types/ets_promise.h"
18 #include "plugins/ets/runtime/ets_coroutine.h"
19 #include "plugins/ets/runtime/ets_vm.h"
20 #include "plugins/ets/runtime/ets_callback.h"
21 
22 namespace ark::ets {
23 
24 /*static*/
Create(EtsCoroutine * etsCoroutine)25 EtsPromise *EtsPromise::Create(EtsCoroutine *etsCoroutine)
26 {
27     EtsClass *klass = etsCoroutine->GetPandaVM()->GetClassLinker()->GetPromiseClass();
28     EtsObject *etsObject = EtsObject::Create(etsCoroutine, klass);
29     return reinterpret_cast<EtsPromise *>(etsObject);
30 }
31 
OnPromiseCompletion(EtsCoroutine * coro)32 void EtsPromise::OnPromiseCompletion(EtsCoroutine *coro)
33 {
34     auto *event = GetEventPtr();
35     // event can be equal to nullptr in case of GENERIC CoroutineEvent
36     if (event != nullptr) {
37         event->Happen();
38         SetEventPtr(nullptr);
39     }
40 
41     PandaUnorderedMap<EtsCoroutine *, PandaList<PandaUniquePtr<Callback>>> readyCallbacks;
42     auto *cbQueue = GetCallbackQueue(coro);
43     auto *coroPtrQueue = GetCoroPtrQueue(coro);
44     auto queueSize = GetQueueSize();
45 
46     for (int idx = 0; idx < queueSize; ++idx) {
47         auto *callbackCoro = reinterpret_cast<EtsCoroutine *>(coroPtrQueue->Get(idx));
48         auto *thenCallback = cbQueue->Get(idx);
49         auto callback = EtsCallback::Create(coro, thenCallback);
50         readyCallbacks[callbackCoro].push_back(std::move(callback));
51     }
52 
53     ClearQueues(coro);
54     for (auto &[callbackCoro, callbacks] : readyCallbacks) {
55         callbackCoro->AcceptAnnouncedCallbacks(std::move(callbacks));
56     }
57 }
58 
EnsureCapacity(EtsCoroutine * coro)59 void EtsPromise::EnsureCapacity(EtsCoroutine *coro)
60 {
61     int queueLength = GetCallbackQueue(coro) == nullptr ? 0 : GetCallbackQueue(coro)->GetLength();
62     if (queueSize_ > queueLength) {
63         return;
64     }
65     auto newQueueLength = queueLength * 2U + 1U;
66     auto *objectClass = coro->GetPandaVM()->GetClassLinker()->GetObjectClass();
67     auto *tmpCbQueue = EtsObjectArray::Create(objectClass, newQueueLength);
68     if (queueSize_ != 0) {
69         GetCallbackQueue(coro)->CopyDataTo(tmpCbQueue);
70     }
71     ObjectAccessor::SetObject(coro, this, MEMBER_OFFSET(EtsPromise, callbackQueue_), tmpCbQueue->GetCoreType());
72     auto *newCoroPtrQueue = EtsLongArray::Create(newQueueLength);
73     if (queueSize_ != 0) {
74         auto *coroPtrQueueData = GetCoroPtrQueue(coro)->GetData<EtsCoroutine *>();
75         [[maybe_unused]] auto err =
76             memcpy_s(newCoroPtrQueue->GetData<EtsCoroutine *>(), newQueueLength * sizeof(EtsLong), coroPtrQueueData,
77                      queueLength * sizeof(EtsCoroutine *));
78         ASSERT(err == EOK);
79     }
80     ObjectAccessor::SetObject(coro, this, MEMBER_OFFSET(EtsPromise, coroPtrQueue_), newCoroPtrQueue->GetCoreType());
81 }
82 
PromotePromiseRef(EtsCoroutine * coro)83 void EtsPromise::PromotePromiseRef(EtsCoroutine *coro)
84 {
85     auto *event = GetEventPtr();
86     // event can be equal to nullptr in case of GENERIC CoroutineEvent
87     if (event == nullptr || event->GetType() != CoroutineEvent::Type::COMPLETION) {
88         return;
89     }
90     auto *completionEvent = static_cast<CompletionEvent *>(event);
91     os::memory::LockHolder lh(*completionEvent);
92     auto *promiseRef = completionEvent->ReleasePromise();
93     // promiseRef can be equal to nullptr in case of concurrent Promise.resolve
94     if (promiseRef == nullptr || promiseRef->IsGlobal()) {
95         completionEvent->SetPromise(promiseRef);
96         return;
97     }
98     ASSERT(promiseRef->IsWeak());
99     auto *storage = coro->GetPandaVM()->GetGlobalObjectStorage();
100     auto *globalPromiseRef = storage->Add(this, mem::Reference::ObjectType::GLOBAL);
101     completionEvent->SetPromise(globalPromiseRef);
102     storage->Remove(promiseRef);
103 }
104 
GetOrCreateEventPtr()105 CoroutineEvent *EtsPromise::GetOrCreateEventPtr()
106 {
107     ASSERT(IsLocked());
108     auto *event = GetEventPtr();
109     if (event != nullptr) {
110         if (event->GetType() == CoroutineEvent::Type::GENERIC) {
111             eventRefCounter_++;
112         }
113         return event;
114     }
115     ASSERT(eventRefCounter_ == 0);
116     auto *coroManager = EtsCoroutine::GetCurrent()->GetCoroutineManager();
117     event = Runtime::GetCurrent()->GetInternalAllocator()->New<GenericEvent>(coroManager);
118     eventRefCounter_++;
119     SetEventPtr(event);
120     return event;
121 }
122 
RetireEventPtr(CoroutineEvent * event)123 void EtsPromise::RetireEventPtr(CoroutineEvent *event)
124 {
125     ASSERT(event != nullptr);
126     os::memory::LockHolder lk(*this);
127     ASSERT(event->GetType() == CoroutineEvent::Type::GENERIC);
128     ASSERT(GetEventPtr() == event || GetEventPtr() == nullptr);
129     if (eventRefCounter_-- == 1) {
130         Runtime::GetCurrent()->GetInternalAllocator()->Delete(event);
131         SetEventPtr(nullptr);
132     }
133 }
134 
135 }  // namespace ark::ets
136