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/ets_utils.h"
17 #include "plugins/ets/runtime/ets_vm.h"
18 #include "plugins/ets/runtime/intrinsics/gc_task_tracker.h"
19
20 namespace ark::ets::intrinsics {
21
22 GCTaskTracker g_gcTaskTracker; // NOLINT(fuchsia-statically-constructed-objects)
23 os::memory::Mutex GCTaskTracker::lock_; // NOLINT(fuchsia-statically-constructed-objects)
24 bool GCTaskTracker::initialized_ = false;
25
26 /* static */
InitIfNeededAndGet(mem::GC * gc)27 GCTaskTracker &GCTaskTracker::InitIfNeededAndGet(mem::GC *gc)
28 {
29 os::memory::LockHolder lh(lock_);
30 if (initialized_) {
31 return g_gcTaskTracker;
32 }
33 gc->AddListener(&g_gcTaskTracker);
34 initialized_ = true;
35 return g_gcTaskTracker;
36 }
37
38 /* static */
IsInitialized()39 bool GCTaskTracker::IsInitialized()
40 {
41 os::memory::LockHolder lh(lock_);
42 return initialized_;
43 }
44
AddTaskId(uint64_t id)45 void GCTaskTracker::AddTaskId(uint64_t id)
46 {
47 os::memory::LockHolder lock(lock_);
48 taskIds_.push_back(id);
49 }
50
HasId(uint64_t id)51 bool GCTaskTracker::HasId(uint64_t id)
52 {
53 os::memory::LockHolder lock(lock_);
54 return std::find(taskIds_.begin(), taskIds_.end(), id) != taskIds_.end();
55 }
56
SetCallbackForTask(uint32_t taskId,mem::Reference * callbackRef)57 void GCTaskTracker::SetCallbackForTask(uint32_t taskId, mem::Reference *callbackRef)
58 {
59 callbackTaskId_ = taskId;
60 callbackRef_ = callbackRef;
61 }
62
GCStarted(const GCTask & task,size_t heapSize)63 void GCTaskTracker::GCStarted(const GCTask &task, [[maybe_unused]] size_t heapSize)
64 {
65 currentTaskId_ = task.GetId();
66 }
67
GCPhaseStarted(mem::GCPhase phase)68 void GCTaskTracker::GCPhaseStarted(mem::GCPhase phase)
69 {
70 if (phase != mem::GCPhase::GC_PHASE_MARK || callbackRef_ == nullptr || currentTaskId_ != callbackTaskId_) {
71 return;
72 }
73 auto *coroutine = EtsCoroutine::GetCurrent();
74 ASSERT(coroutine != nullptr);
75 auto *obj = reinterpret_cast<EtsObject *>(coroutine->GetPandaVM()->GetGlobalObjectStorage()->Get(callbackRef_));
76 Value arg(obj->GetCoreType());
77 os::memory::ReadLockHolder lock(*coroutine->GetPandaVM()->GetRendezvous()->GetMutatorLock());
78 LambdaUtils::InvokeVoid(coroutine, obj);
79 }
80
GCFinished(const GCTask & task,size_t heapSizeBeforeGc,size_t heapSize)81 void GCTaskTracker::GCFinished(const GCTask &task, [[maybe_unused]] size_t heapSizeBeforeGc,
82 [[maybe_unused]] size_t heapSize)
83 {
84 RemoveId(task.GetId());
85 }
86
RemoveId(uint64_t id)87 void GCTaskTracker::RemoveId(uint64_t id)
88 {
89 currentTaskId_ = 0;
90 if (id == callbackTaskId_ && callbackRef_ != nullptr) {
91 auto *coroutine = EtsCoroutine::GetCurrent();
92 ASSERT(coroutine != nullptr);
93 coroutine->GetPandaVM()->GetGlobalObjectStorage()->Remove(callbackRef_);
94 callbackRef_ = nullptr;
95 }
96 if (id != 0) {
97 os::memory::LockHolder lock(lock_);
98 auto it = std::find(taskIds_.begin(), taskIds_.end(), id);
99 // There may be no such id if the corresponding GC has been triggered not by startGC
100 if (it != taskIds_.end()) {
101 taskIds_.erase(it);
102 }
103 }
104 }
105
106 } // namespace ark::ets::intrinsics
107