• 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/finalreg/finalization_registry_manager.h"
17 #include "plugins/ets/runtime/ets_class_linker_context.h"
18 #include "plugins/ets/runtime/types/ets_array.h"
19 #include "plugins/ets/runtime/types/ets_method.h"
20 
21 namespace ark::ets {
22 
SortInstancies()23 void FinalizationRegistryManager::SortInstancies()
24 {
25     auto *objArray = EtsObjectArray::FromCoreType(vm_->GetGlobalObjectStorage()->Get(finRegInstancies_));
26     ASSERT(objArray != nullptr);
27     size_t head = 0;
28     size_t localIndex = objArray->GetLength();
29     size_t tail = localIndex - 1;
30     while (head < tail) {
31         while (head < tail && objArray->Get(head) != nullptr) {
32             head++;
33         }
34         while (head < tail && objArray->Get(tail) == nullptr) {
35             tail--;
36         }
37         if (head < tail) {
38             objArray->Set(head, objArray->Get(tail));
39             objArray->Set(tail, nullptr);
40             localIndex = tail;
41         }
42     }
43     finRegLastIndex_ = localIndex;
44 }
45 
EnsureCapacity(EtsCoroutine * coro)46 void FinalizationRegistryManager::EnsureCapacity(EtsCoroutine *coro)
47 {
48     EtsClass *objectClass = vm_->GetClassLinker()->GetClassRoot(EtsClassRoot::OBJECT);
49     if (finRegInstancies_ == nullptr) {
50         auto *objArray = EtsObjectArray::Create(objectClass, INIT_SIZE, SpaceType::SPACE_TYPE_NON_MOVABLE_OBJECT);
51         ASSERT(objArray != nullptr);
52         finRegInstancies_ =
53             vm_->GetGlobalObjectStorage()->Add(objArray->GetCoreType(), ark::mem::Reference::ObjectType::GLOBAL);
54         finRegLastIndex_ = 0;
55     }
56     auto *objArray = EtsObjectArray::FromCoreType(vm_->GetGlobalObjectStorage()->Get(finRegInstancies_));
57     EtsHandle<EtsObjectArray> objArrayHandle(coro, objArray);
58     ASSERT(objArrayHandle.GetPtr() != nullptr);
59     size_t finRegCapacity = objArrayHandle->GetLength();
60     if (finRegLastIndex_ >= finRegCapacity) {
61         SortInstancies();
62         if (finRegLastIndex_ >= finRegCapacity) {
63             auto *newFinalizationRegistryInstances = EtsObjectArray::Create(objectClass, (finRegCapacity * 2U) + 1U,
64                                                                             SpaceType::SPACE_TYPE_NON_MOVABLE_OBJECT);
65             objArrayHandle->CopyDataTo(newFinalizationRegistryInstances);
66             vm_->GetGlobalObjectStorage()->Remove(finRegInstancies_);
67             finRegInstancies_ = vm_->GetGlobalObjectStorage()->Add(newFinalizationRegistryInstances->GetCoreType(),
68                                                                    ark::mem::Reference::ObjectType::GLOBAL);
69         }
70     }
71 }
72 
RegisterInstance(EtsObject * instance)73 void FinalizationRegistryManager::RegisterInstance(EtsObject *instance)
74 {
75     ASSERT_MANAGED_CODE();
76     EtsCoroutine *coroutine = EtsCoroutine::GetCurrent();
77     [[maybe_unused]] EtsHandleScope scope(coroutine);
78     EtsHandle<EtsObject> instanceHandle(coroutine, instance);
79     EnsureCapacity(coroutine);
80     auto *objArray = EtsObjectArray::FromCoreType(vm_->GetGlobalObjectStorage()->Get(finRegInstancies_));
81     ASSERT(objArray != nullptr);
82     ASSERT(objArray->GetLength() != 0);
83     objArray->Set(finRegLastIndex_, instanceHandle.GetPtr());
84     finRegLastIndex_++;
85 }
86 
CleanupCoroFinished()87 void FinalizationRegistryManager::CleanupCoroFinished()
88 {
89     // Atomic with acq_rel order reason: other threads should see correct value
90     [[maybe_unused]] uint32_t oldCnt = finRegCleanupCoroCount_.fetch_sub(1, std::memory_order_acq_rel);
91     ASSERT(oldCnt > 0);
92 }
93 
UpdateFinRegCoroCountAndCheckIfCleanupNeeded()94 bool FinalizationRegistryManager::UpdateFinRegCoroCountAndCheckIfCleanupNeeded()
95 {
96     // Atomic with acquire order reason: getting correct value
97     uint32_t cnt = finRegCleanupCoroCount_.load(std::memory_order_acquire);
98     uint32_t oldCnt = cnt;
99     // Atomic with acq_rel order reason: sync for counter
100     while (cnt < MAX_FINREG_CLEANUP_COROS && !finRegCleanupCoroCount_.compare_exchange_weak(
101                                                  // CC-OFFNXT(G.FMT.06-CPP) project code style
102                                                  cnt, cnt + 1U, std::memory_order_acq_rel, std::memory_order_acquire)) {
103         oldCnt = cnt;
104     }
105     return oldCnt < MAX_FINREG_CLEANUP_COROS;
106 }
107 
StartCleanupCoroIfNeeded(EtsCoroutine * coro)108 void FinalizationRegistryManager::StartCleanupCoroIfNeeded(EtsCoroutine *coro)
109 {
110     ASSERT(coro != nullptr);
111     auto *coroManager = coro->GetCoroutineManager();
112 
113     if (finRegLastIndex_ != 0 && UpdateFinRegCoroCountAndCheckIfCleanupNeeded()) {
114         auto *objArray = EtsObjectArray::FromCoreType(vm_->GetGlobalObjectStorage()->Get(finRegInstancies_));
115         auto *event = Runtime::GetCurrent()->GetInternalAllocator()->New<CompletionEvent>(nullptr, coroManager);
116         Method *cleanup = PlatformTypes(vm_)->coreFinalizationRegistryExecCleanup->GetPandaMethod();
117         auto launchMode =
118             coroManager->IsMainWorker(coro) ? CoroutineLaunchMode::MAIN_WORKER : CoroutineLaunchMode::DEFAULT;
119         auto args = PandaVector<Value> {Value(objArray->GetCoreType()), Value(static_cast<uint32_t>(launchMode))};
120         [[maybe_unused]] bool launchResult = coroManager->Launch(event, cleanup, std::move(args), launchMode,
121                                                                  CoroutinePriority::DEFAULT_PRIORITY, false);
122         ASSERT(launchResult);
123     }
124 }
125 
126 }  // namespace ark::ets
127