1 /*
2 * Copyright (c) 2021 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 #ifndef ECMASCRIPT_MEM_PARALLEL_EVACUATOR_INL_H
17 #define ECMASCRIPT_MEM_PARALLEL_EVACUATOR_INL_H
18
19 #include "ecmascript/mem/parallel_evacuator.h"
20
21 #include "ecmascript/mem/heap.h"
22 #include "ecmascript/mem/mark_word.h"
23 #include "ecmascript/mem/region-inl.h"
24 #include "ecmascript/taskpool/taskpool.h"
25
26 namespace panda::ecmascript {
27 // Move regions with a survival rate of more than 75% to new space
IsWholeRegionEvacuate(Region * region)28 bool ParallelEvacuator::IsWholeRegionEvacuate(Region *region)
29 {
30 return (static_cast<double>(region->AliveObject()) / region->GetSize()) > MIN_OBJECT_SURVIVAL_RATE &&
31 !region->HasAgeMark();
32 }
33
34 template <typename Callback>
VisitBodyInObj(TaggedObject * root,ObjectSlot start,ObjectSlot end,Callback callback)35 bool ParallelEvacuator::VisitBodyInObj(
36 TaggedObject *root, ObjectSlot start, ObjectSlot end, Callback callback)
37 {
38 auto hclass = root->GetClass();
39 ASSERT(!hclass->IsAllTaggedProp());
40 int index = 0;
41 TaggedObject *dst = hclass->GetLayout().GetTaggedObject();
42 auto layout = LayoutInfo::UncheckCast(dst);
43 ObjectSlot realEnd = start;
44 realEnd += layout->GetPropertiesCapacity();
45 end = end > realEnd ? realEnd : end;
46 for (ObjectSlot slot = start; slot < end; slot++) {
47 auto attr = layout->GetAttr(index++);
48 if (attr.IsTaggedRep()) {
49 callback(slot);
50 }
51 }
52 return true;
53 }
54
UpdateOldToNewObjectSlot(ObjectSlot & slot)55 bool ParallelEvacuator::UpdateOldToNewObjectSlot(ObjectSlot &slot)
56 {
57 JSTaggedValue value(slot.GetTaggedType());
58 if (value.IsHeapObject()) {
59 TaggedObject *object = value.GetHeapObject();
60 Region *valueRegion = Region::ObjectAddressToRange(object);
61
62 // It is only update old to new object when iterate OldToNewRSet
63 if (valueRegion->InYoungSpace()) {
64 if (!valueRegion->InNewToNewSet()) {
65 MarkWord markWord(object);
66 if (markWord.IsForwardingAddress()) {
67 TaggedObject *dst = markWord.ToForwardingAddress();
68 if (value.IsWeakForHeapObject()) {
69 dst = JSTaggedValue(dst).CreateAndGetWeakRef().GetRawTaggedObject();
70 }
71 slot.Update(dst);
72 Region *dstRegion = Region::ObjectAddressToRange(dst);
73 // Keep oldtonewrset when object move fromspace to tospace
74 if (dstRegion->InYoungSpace()) {
75 return true;
76 }
77 } else {
78 if (value.IsWeakForHeapObject()) {
79 slot.Clear();
80 }
81 }
82 } else {
83 // move region from fromspace to tospace
84 if (valueRegion->Test(object)) {
85 return true;
86 } else {
87 if (value.IsWeakForHeapObject()) {
88 slot.Clear();
89 }
90 }
91 }
92 }
93 }
94 return false;
95 }
96
UpdateObjectSlot(ObjectSlot & slot)97 void ParallelEvacuator::UpdateObjectSlot(ObjectSlot &slot)
98 {
99 JSTaggedValue value(slot.GetTaggedType());
100 if (value.IsHeapObject()) {
101 if (value.IsWeakForHeapObject()) {
102 return UpdateWeakObjectSlot(value.GetTaggedWeakRef(), slot);
103 }
104 TaggedObject *object = value.GetTaggedObject();
105 MarkWord markWord(object);
106 if (markWord.IsForwardingAddress()) {
107 TaggedObject *dst = markWord.ToForwardingAddress();
108 slot.Update(dst);
109 }
110 }
111 }
112
UpdateWeakObjectSlot(TaggedObject * value,ObjectSlot & slot)113 void ParallelEvacuator::UpdateWeakObjectSlot(TaggedObject *value, ObjectSlot &slot)
114 {
115 Region *objectRegion = Region::ObjectAddressToRange(value);
116 if (objectRegion->InYoungSpaceOrCSet()) {
117 if (objectRegion->InNewToNewSet()) {
118 if (!objectRegion->Test(value)) {
119 slot.Clear();
120 }
121 } else {
122 MarkWord markWord(value);
123 if (markWord.IsForwardingAddress()) {
124 TaggedObject *dst = markWord.ToForwardingAddress();
125 auto weakRef = JSTaggedValue(dst).CreateAndGetWeakRef().GetRawTaggedObject();
126 slot.Update(weakRef);
127 return;
128 }
129 slot.Clear();
130 }
131 return;
132 }
133
134 if (heap_->IsConcurrentFullMark()) {
135 if (!objectRegion->Test(value)) {
136 slot.Clear();
137 }
138 }
139 }
140
SetObjectFieldRSet(TaggedObject * object,JSHClass * cls)141 void ParallelEvacuator::SetObjectFieldRSet(TaggedObject *object, JSHClass *cls)
142 {
143 Region *region = Region::ObjectAddressToRange(object);
144 auto callbackWithCSet = [this, region](TaggedObject *root, ObjectSlot start, ObjectSlot end, VisitObjectArea area) {
145 if (area == VisitObjectArea::IN_OBJECT) {
146 if (VisitBodyInObj(root, start, end, [&](ObjectSlot slot) { SetObjectRSet(slot, region); })) {
147 return;
148 };
149 }
150 for (ObjectSlot slot = start; slot < end; slot++) {
151 SetObjectRSet(slot, region);
152 }
153 };
154 objXRay_.VisitObjectBody<VisitType::OLD_GC_VISIT>(object, cls, callbackWithCSet);
155 }
156
SetObjectRSet(ObjectSlot slot,Region * region)157 void ParallelEvacuator::SetObjectRSet(ObjectSlot slot, Region *region)
158 {
159 JSTaggedType value = slot.GetTaggedType();
160 if (!JSTaggedValue(value).IsHeapObject()) {
161 return;
162 }
163 Region *valueRegion = Region::ObjectAddressToRange(value);
164 if (valueRegion->InYoungSpace()) {
165 region->InsertOldToNewRSet(slot.SlotAddress());
166 } else if (valueRegion->InCollectSet() || JSTaggedValue(value).IsWeakForHeapObject()) {
167 region->InsertCrossRegionRSet(slot.SlotAddress());
168 }
169 }
170
GetWorkloadSafe()171 std::unique_ptr<ParallelEvacuator::Workload> ParallelEvacuator::GetWorkloadSafe()
172 {
173 LockHolder holder(mutex_);
174 std::unique_ptr<Workload> unit;
175 if (!workloads_.empty()) {
176 unit = std::move(workloads_.back());
177 workloads_.pop_back();
178 }
179 return unit;
180 }
181
AddWorkload(std::unique_ptr<Workload> region)182 void ParallelEvacuator::AddWorkload(std::unique_ptr<Workload> region)
183 {
184 workloads_.emplace_back(std::move(region));
185 }
186
UpdateAddressAfterEvacation(TaggedObject * oldAddress)187 TaggedObject* ParallelEvacuator::UpdateAddressAfterEvacation(TaggedObject *oldAddress)
188 {
189 Region *objectRegion = Region::ObjectAddressToRange(reinterpret_cast<TaggedObject *>(oldAddress));
190 if (!objectRegion) {
191 return nullptr;
192 }
193 if (objectRegion->InYoungSpaceOrCSet()) {
194 if (objectRegion->InNewToNewSet()) {
195 if (objectRegion->Test(oldAddress)) {
196 return oldAddress;
197 }
198 } else {
199 MarkWord markWord(oldAddress);
200 if (markWord.IsForwardingAddress()) {
201 return markWord.ToForwardingAddress();
202 }
203 }
204 return nullptr;
205 }
206 if (heap_->IsConcurrentFullMark()) {
207 if (objectRegion->GetMarkGCBitset() == nullptr || !objectRegion->Test(oldAddress)) {
208 return nullptr;
209 }
210 }
211 return oldAddress;
212 }
213
CalculateEvacuationThreadNum()214 int ParallelEvacuator::CalculateEvacuationThreadNum()
215 {
216 uint32_t length = workloads_.size();
217 uint32_t regionPerThread = 8;
218 uint32_t maxThreadNum = std::min(heap_->GetMaxEvacuateTaskCount(),
219 Taskpool::GetCurrentTaskpool()->GetTotalThreadNum());
220 return static_cast<int>(std::min(std::max(1U, length / regionPerThread), maxThreadNum));
221 }
222
CalculateUpdateThreadNum()223 int ParallelEvacuator::CalculateUpdateThreadNum()
224 {
225 uint32_t length = workloads_.size();
226 double regionPerThread = 1.0 / 4;
227 length = std::pow(length, regionPerThread);
228 uint32_t maxThreadNum = std::min(heap_->GetMaxEvacuateTaskCount(),
229 Taskpool::GetCurrentTaskpool()->GetTotalThreadNum());
230 return static_cast<int>(std::min(std::max(1U, length), maxThreadNum));
231 }
232 } // namespace panda::ecmascript
233 #endif // ECMASCRIPT_MEM_PARALLEL_EVACUATOR_INL_H
234