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