• 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 "ecmascript/mem/shared_heap/shared_gc_evacuator.h"
17 
18 #include "common_components/taskpool/taskpool.h"
19 #include "ecmascript/mem/object_xray.h"
20 #include "ecmascript/mem/tlab_allocator-inl.h"
21 
22 namespace panda::ecmascript {
Evacuate()23 void SharedGCEvacuator::Evacuate()
24 {
25     EvacuateRegions();
26     UpdateReference();
27 }
28 
EvacuateRegions()29 void SharedGCEvacuator::EvacuateRegions()
30 {
31     TRACE_GC(GCStats::Scope::ScopeId::Evacuate,  sHeap_->GetEcmaGCStats());
32     ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, ("SharedGCEvacuator::EvacuateRegions;cset count: "
33         + std::to_string(sHeap_->GetOldSpace()->GetCollectSetRegionCount())).c_str(), "");
34     auto sTlabAllocator = new SharedTlabAllocator(sHeap_);
35     auto inHeapProfiler = sHeap_->InHeapProfiler();
36     sHeap_->GetOldSpace()->EnumerateCollectRegionSet([this, inHeapProfiler, sTlabAllocator](Region *region) {
37         region->IterateAllMarkedBits([this, inHeapProfiler, sTlabAllocator](void *mem) {
38             auto header = reinterpret_cast<TaggedObject *>(mem);
39             JSHClass *klass = header->GetClass();
40             size_t size = header->GetSize();
41             uintptr_t address = sTlabAllocator->Allocate(size, SHARED_COMPRESS_SPACE);
42             ASSERT(address != 0);
43             if (memcpy_s(ToVoidPtr(address), size, ToVoidPtr(ToUintPtr(mem)), size) != EOK) { // LOCV_EXCL_BR_LINE
44                 LOG_ECMA_MEM(FATAL) << "memcpy_s failed";
45                 UNREACHABLE();
46             }
47             if (UNLIKELY(inHeapProfiler)) {
48                 sHeap_->OnMoveEvent(reinterpret_cast<intptr_t>(mem), reinterpret_cast<TaggedObject *>(address), size);
49             }
50             Barriers::SetPrimitive(header, 0, MarkWord::FromForwardingAddress(address));
51             ProcessObjectField(reinterpret_cast<TaggedObject *>(address), klass);
52         });
53         sHeap_->GetOldSpace()->DecreaseCommitted(region->GetCapacity());
54         sHeap_->GetOldSpace()->DecreaseObjectSize(region->GetSize());
55     });
56     sTlabAllocator->Finalize();
57     delete sTlabAllocator;
58 }
59 
UpdateReference()60 void SharedGCEvacuator::UpdateReference()
61 {
62     TRACE_GC(GCStats::Scope::ScopeId::UpdateReference,  sHeap_->GetEcmaGCStats());
63     ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, "SharedGCEvacuator::UpdateReference", "");
64     Runtime *runtime = Runtime::GetInstance();
65     runtime->GCIterateThreadList([this](JSThread *thread) {
66         ASSERT(!thread->IsInRunningState());
67         auto heap = const_cast<Heap*>(thread->GetEcmaVM()->GetHeap());
68         heap->GetSweeper()->EnsureAllTaskFinished();
69         heap->EnumerateRegions([this](Region *region) {
70             AddWorkload(std::make_unique<UpdateLocalReferenceWorkload>(this, region));
71         });
72     });
73     sHeap_->EnumerateOldSpaceRegions([this](Region *region) {
74         AddWorkload(std::make_unique<UpdateSharedReferenceWorkload>(this, region));
75     });
76     if (sHeap_->IsParallelGCEnabled()) {
77         LockHolder holder(lock_);
78         parallel_ = CalculateUpdateThreadNum();
79         auto dTid = DaemonThread::GetInstance()->GetThreadId();
80         for (int i = 0; i < parallel_; i++) {
81             common::Taskpool::GetCurrentTaskpool()->PostTask(std::make_unique<UpdateReferenceTask>(dTid, this));
82         }
83     }
84     runtime->IterateSharedRoot(rootVisitor_);
85     runtime->GCIterateThreadList([this](JSThread *thread) {
86         ASSERT(!thread->IsInRunningState());
87         auto vm = thread->GetEcmaVM();
88         ObjectXRay::VisitVMRoots(vm, rootVisitor_);
89     });
90     ProcessWorkloads(true);
91     WaitFinished();
92 }
93 
Process(bool isMain)94 void SharedGCEvacuator::UpdateLocalReferenceWorkload::Process([[maybe_unused]]bool isMain)
95 {
96     region_->IterateAllLocalToShareBits([this](void *mem) {
97         ObjectSlot slot(ToUintPtr(mem));
98         return evacuator_->UpdateObjectSlot(slot);
99     });
100 }
101 
Process(bool isMain)102 void SharedGCEvacuator::UpdateSharedReferenceWorkload::Process([[maybe_unused]]bool isMain)
103 {
104     region_->IterateAllCrossRegionBits([this](void *mem) {
105         ObjectSlot slot(ToUintPtr(mem));
106         evacuator_->UpdateObjectSlot(slot);
107     });
108 }
109 
Run(uint32_t threadIndex)110 bool SharedGCEvacuator::UpdateReferenceTask::Run([[maybe_unused]] uint32_t threadIndex)
111 {
112     ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, "SharedGCEvacuator::UpdateReferenceTask", "");
113     evacuator_->ProcessWorkloads(false);
114     return true;
115 }
116 
WaitFinished()117 void SharedGCEvacuator::WaitFinished()
118 {
119     if (parallel_ > 0) {
120         LockHolder holder(lock_);
121         while (parallel_ > 0) {
122             condition_.Wait(&lock_);
123         }
124     }
125 }
126 
CalculateUpdateThreadNum()127 int SharedGCEvacuator::CalculateUpdateThreadNum()
128 {
129     uint32_t count = workloads_.size();
130     constexpr double RATIO = 1.0 / 4;
131     count = std::pow(count, RATIO);
132     return static_cast<int>(std::min(std::max(1U, count), common::Taskpool::GetCurrentTaskpool()->GetTotalThreadNum()));
133 }
134 
UpdateObjectSlot(ObjectSlot slot)135 bool SharedGCEvacuator::UpdateObjectSlot(ObjectSlot slot)
136 {
137     JSTaggedValue value(slot.GetTaggedType());
138     if (!value.IsHeapObject()) {
139         return false;
140     }
141     Region *region = Region::ObjectAddressToRange(slot.GetTaggedType());
142     if (!region->InSCollectSet()) {
143         return true;
144     }
145     ASSERT(region->InSharedHeap());
146     bool isWeak = value.IsWeakForHeapObject();
147     TaggedObject *object = value.GetHeapObject();
148     MarkWord markWord(object);
149     if (markWord.IsForwardingAddress()) {
150         TaggedObject *dst = markWord.ToForwardingAddress();
151         if (isWeak) {
152             dst = JSTaggedValue(dst).CreateAndGetWeakRef().GetRawTaggedObject();
153         }
154         slot.Update(dst);
155         return true;
156     } else {
157         slot.Clear();
158         return false;
159     }
160 }
161 
VisitObjectRangeImpl(BaseObject * root,uintptr_t startAddr,uintptr_t endAddr,VisitObjectArea area)162 void SharedGCEvacuator::ObjectFieldCSetVisitor::VisitObjectRangeImpl(BaseObject *root, uintptr_t startAddr,
163     uintptr_t endAddr, VisitObjectArea area)
164 {
165     Region *rootRegion = Region::ObjectAddressToRange(root);
166     ObjectSlot start(startAddr);
167     ObjectSlot end(endAddr);
168     if (UNLIKELY(area == VisitObjectArea::IN_OBJECT)) {
169         JSHClass *hclass = TaggedObject::Cast(root)->GetClass();
170         ASSERT(!hclass->IsAllTaggedProp());
171         int index = 0;
172         TaggedObject *dst = hclass->GetLayout(THREAD_ARG_PLACEHOLDER).GetTaggedObject();
173         LayoutInfo *layout = LayoutInfo::UncheckCast(dst);
174         ObjectSlot realEnd = start;
175         realEnd += layout->GetPropertiesCapacity();
176         end = end > realEnd ? realEnd : end;
177         for (ObjectSlot slot = start; slot < end; slot++) {
178             auto attr = layout->GetAttr(THREAD_ARG_PLACEHOLDER, index++);
179             if (attr.IsTaggedRep()) {
180                 evacuator_->UpdateCrossRegionRSet(slot, rootRegion);
181             }
182         }
183         return;
184     }
185     for (ObjectSlot slot = start; slot < end; slot++) {
186         evacuator_->UpdateCrossRegionRSet(slot, rootRegion);
187     }
188 }
189 
ProcessObjectField(TaggedObject * object,JSHClass * hclass)190 void SharedGCEvacuator::ProcessObjectField(TaggedObject *object, JSHClass *hclass)
191 {
192     ObjectXRay::VisitObjectBody<VisitType::OLD_GC_VISIT>(object, hclass, objectFieldCSetVisitor_);
193 }
194 
UpdateCrossRegionRSet(ObjectSlot slot,Region * objectRegion)195 void SharedGCEvacuator::UpdateCrossRegionRSet(ObjectSlot slot, Region *objectRegion)
196 {
197     JSTaggedType value = slot.GetTaggedType();
198     if (!JSTaggedValue(value).IsHeapObject()) {
199         return;
200     }
201     Region *valueRegion = Region::ObjectAddressToRange(value);
202     if (valueRegion->InSCollectSet()) {
203         objectRegion->InsertCrossRegionRSet(slot.SlotAddress());
204     }
205 }
206 
VisitRoot(Root type,ObjectSlot slot)207 void SharedGCEvacuator::UpdateRootVisitor::VisitRoot([[maybe_unused]] Root type, ObjectSlot slot)
208 {
209     UpdateObjectSlotRoot(slot);
210 }
211 
VisitRangeRoot(Root type,ObjectSlot start,ObjectSlot end)212 void SharedGCEvacuator::UpdateRootVisitor::VisitRangeRoot([[maybe_unused]] Root type, ObjectSlot start, ObjectSlot end)
213 {
214     for (ObjectSlot slot = start; slot < end; slot++) {
215         UpdateObjectSlotRoot(slot);
216     }
217 }
218 
VisitBaseAndDerivedRoot(Root type,ObjectSlot base,ObjectSlot derived,uintptr_t baseOldObject)219 void SharedGCEvacuator::UpdateRootVisitor::VisitBaseAndDerivedRoot([[maybe_unused]] Root type, ObjectSlot base,
220                                                                    ObjectSlot derived, uintptr_t baseOldObject)
221 {
222     if (JSTaggedValue(base.GetTaggedType()).IsHeapObject()) {
223         derived.Update(base.GetTaggedType() + derived.GetTaggedType() - baseOldObject);
224     }
225 }
226 
UpdateObjectSlotRoot(ObjectSlot slot)227 void SharedGCEvacuator::UpdateRootVisitor::UpdateObjectSlotRoot(ObjectSlot slot)
228 {
229     JSTaggedValue value(slot.GetTaggedType());
230     if (value.IsHeapObject()) {
231         Region *region = Region::ObjectAddressToRange(slot.GetTaggedType());
232         if (region->InSCollectSet()) {
233             ASSERT(region->InSharedHeap());
234             ASSERT(!value.IsWeakForHeapObject());
235             TaggedObject *object = value.GetHeapObject();
236             MarkWord markWord(object);
237             if (markWord.IsForwardingAddress()) {
238                 TaggedObject *dst = markWord.ToForwardingAddress();
239                 slot.Update(dst);
240             } else {
241                 slot.Clear();
242             }
243         }
244     }
245 }
246 }  // namespace panda::ecmascript
247