• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 
16 #include "plugins/ets/runtime/interop_js/sts_vm_interface_impl.h"
17 #include "plugins/ets/runtime/interop_js/xgc/xgc.h"
18 
19 namespace ark::ets::interop::js {
20 
21 thread_local STSVMInterfaceImpl::XGCSyncState STSVMInterfaceImpl::xgcSyncState_ =
22     STSVMInterfaceImpl::XGCSyncState::NONE;
23 
MarkFromObject(void * obj)24 void STSVMInterfaceImpl::MarkFromObject(void *obj)
25 {
26     XGC::GetInstance()->MarkFromObject(obj);
27 }
28 
STSVMInterfaceImpl()29 STSVMInterfaceImpl::STSVMInterfaceImpl() : xgcBarrier_(STSVMInterface::DEFAULT_XGC_EXECUTORS_COUNT) {}
30 
OnVMAttach()31 void STSVMInterfaceImpl::OnVMAttach()
32 {
33     xgcBarrier_.Increment();
34 }
35 
OnVMDetach()36 void STSVMInterfaceImpl::OnVMDetach()
37 {
38     xgcBarrier_.Decrement();
39 }
40 
StartXGCBarrier(const NoWorkPred & func)41 bool STSVMInterfaceImpl::StartXGCBarrier(const NoWorkPred &func)
42 {
43     ASSERT(xgcSyncState_ == XGCSyncState::NONE);
44     auto res = xgcBarrier_.InitialWait(func);
45     if (res) {
46         xgcSyncState_ = XGCSyncState::CONCURRENT_PHASE;
47     }
48     return res;
49 }
50 
WaitForConcurrentMark(const NoWorkPred & func)51 bool STSVMInterfaceImpl::WaitForConcurrentMark(const NoWorkPred &func)
52 {
53     ASSERT(xgcSyncState_ == XGCSyncState::CONCURRENT_PHASE);
54     auto res = xgcBarrier_.Wait(func);
55     if (res) {
56         xgcSyncState_ = XGCSyncState::CONCURRENT_FINISHED;
57     }
58     return res;
59 }
60 
RemarkStartBarrier()61 void STSVMInterfaceImpl::RemarkStartBarrier()
62 {
63     ASSERT(xgcSyncState_ == XGCSyncState::CONCURRENT_FINISHED);
64     xgcBarrier_.Wait();
65     xgcSyncState_ = XGCSyncState::REMARK_PHASE;
66 }
67 
WaitForRemark(const NoWorkPred & func)68 bool STSVMInterfaceImpl::WaitForRemark(const NoWorkPred &func)
69 {
70     ASSERT(xgcSyncState_ == XGCSyncState::REMARK_PHASE);
71     auto res = xgcBarrier_.Wait(func);
72     if (res) {
73         xgcSyncState_ = XGCSyncState::NONE;
74     }
75     return res;
76 }
77 
FinishXGCBarrier()78 void STSVMInterfaceImpl::FinishXGCBarrier()
79 {
80     xgcBarrier_.Wait();
81     xgcSyncState_ = XGCSyncState::NONE;
82 }
83 
NotifyWaiters()84 void STSVMInterfaceImpl::NotifyWaiters()
85 {
86     xgcBarrier_.Signal();
87 }
88 
VMBarrier(size_t vmsCount)89 STSVMInterfaceImpl::VMBarrier::VMBarrier(size_t vmsCount)
90 {
91     os::memory::LockHolder lh(barrierMutex_);
92     vmsCount_ = vmsCount;
93     currentVMsCount_ = 0U;
94     epochCount_ = 0U;
95     currentWaitersCount_ = 0U;
96     weakCount_ = 0U;
97 }
98 
Increment()99 void STSVMInterfaceImpl::VMBarrier::Increment()
100 {
101     os::memory::LockHolder lh(barrierMutex_);
102     vmsCount_++;
103 }
104 
Decrement()105 void STSVMInterfaceImpl::VMBarrier::Decrement()
106 {
107     os::memory::LockHolder lh(barrierMutex_);
108     ASSERT(vmsCount_ > 1);  // after this Decrement, barrier is broken and will not wait correctly
109     vmsCount_--;
110     Wake();
111 }
112 
InitialWait(const NoWorkPred & noWorkPred)113 bool STSVMInterfaceImpl::VMBarrier::InitialWait(const NoWorkPred &noWorkPred)
114 {
115     return Wait(noWorkPred, true);
116 }
117 
Wait(const NoWorkPred & noWorkPred)118 bool STSVMInterfaceImpl::VMBarrier::Wait(const NoWorkPred &noWorkPred)
119 {
120     return Wait(noWorkPred, false);
121 }
122 
Wait(const NoWorkPred & noWorkPred,bool isInitial)123 bool STSVMInterfaceImpl::VMBarrier::Wait(const NoWorkPred &noWorkPred, bool isInitial)
124 {
125     os::memory::LockHolder lh(barrierMutex_);
126     // Need check if noWorkPred exist and if yes, check if it's true. This prevent situation with lost Signal.
127     if (CheckNoWorkPred(noWorkPred)) {
128         return false;
129     }
130     size_t epochCount = 0;
131     do {
132         // Save current epoch to look at it in future.
133         epochCount = epochCount_;
134         // No we can try to pass the barrier. First we increment count of waiters.
135         auto currentWaitersCount = IncrementCurrentWaitersCount();
136         // For Inintial barrier we use variable vmsCount_, otherwise we use currentVMsCount_ that can not be checked
137         // between 2 Initial barriers.
138         size_t waitersCount = 0;
139         if (isInitial) {
140             waitersCount = vmsCount_;
141         } else {
142             waitersCount = currentVMsCount_;
143         }
144         // Next we check if this waiter is the last, if it true, we increase epoch and go out
145         if (currentWaitersCount == waitersCount) {
146             // for initial barrier we also should set new currentVMsCount_;
147             if (isInitial) {
148                 currentVMsCount_ = vmsCount_;
149             }
150             epochCount_++;
151             Wake();
152             return true;
153         }
154         // We go to wait, it will return true if noWorkPred() returns true
155         if (WaitNextEpochOrSignal(noWorkPred)) {
156             return false;
157         }
158     } while (epochCount == epochCount_);
159     return true;
160 }
161 
Signal()162 void STSVMInterfaceImpl::VMBarrier::Signal()
163 {
164     os::memory::LockHolder lh(barrierMutex_);
165     Wake();
166 }
167 
IncrementCurrentWaitersCount()168 size_t STSVMInterfaceImpl::VMBarrier::IncrementCurrentWaitersCount()
169 {
170     return ++currentWaitersCount_;
171 }
172 
WaitNextEpochOrSignal(const NoWorkPred & noWorkPred)173 bool STSVMInterfaceImpl::VMBarrier::WaitNextEpochOrSignal(const NoWorkPred &noWorkPred)
174 {
175     size_t weakCount = weakCount_;
176     do {
177         condVar_.Wait(&barrierMutex_);
178         // This while is needed only to avoid problems with spurious wakeups
179     } while (weakCount == weakCount_);
180     return CheckNoWorkPred(noWorkPred);
181 }
182 
Wake()183 void STSVMInterfaceImpl::VMBarrier::Wake()
184 {
185     currentWaitersCount_ = 0;
186     weakCount_++;
187     condVar_.SignalAll();
188 }
189 
190 }  // namespace ark::ets::interop::js
191