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 if (hclass->IsAllTaggedProp()) {
40 return false;
41 }
42 int index = 0;
43 for (ObjectSlot slot = start; slot < end; slot++) {
44 TaggedObject *dst = hclass->GetLayout().GetTaggedObject();
45 MarkWord markWord(dst);
46 if (markWord.IsForwardingAddress()) {
47 dst = markWord.ToForwardingAddress();
48 }
49 auto layout = LayoutInfo::Cast(dst);
50 auto attr = layout->GetAttr(index++);
51 if (attr.IsTaggedRep()) {
52 callback(slot);
53 }
54 }
55 return true;
56 }
57
UpdateOldToNewObjectSlot(ObjectSlot & slot)58 bool ParallelEvacuator::UpdateOldToNewObjectSlot(ObjectSlot &slot)
59 {
60 JSTaggedValue value(slot.GetTaggedType());
61 if (value.IsHeapObject()) {
62 TaggedObject *object = value.GetHeapObject();
63 Region *valueRegion = Region::ObjectAddressToRange(object);
64
65 // It is only update old to new object when iterate OldToNewRSet
66 if (valueRegion->InYoungSpace()) {
67 if (!valueRegion->InNewToNewSet()) {
68 MarkWord markWord(object);
69 if (markWord.IsForwardingAddress()) {
70 TaggedObject *dst = markWord.ToForwardingAddress();
71 if (value.IsWeakForHeapObject()) {
72 dst = JSTaggedValue(dst).CreateAndGetWeakRef().GetRawTaggedObject();
73 }
74 slot.Update(dst);
75 Region *dstRegion = Region::ObjectAddressToRange(dst);
76 // Keep oldtonewrset when object move fromspace to tospace
77 if (dstRegion->InYoungSpace()) {
78 return true;
79 }
80 } else {
81 if (value.IsWeakForHeapObject()) {
82 slot.Clear();
83 }
84 }
85 } else {
86 // move region from fromspace to tospace
87 if (valueRegion->Test(object)) {
88 return true;
89 } else {
90 if (value.IsWeakForHeapObject()) {
91 slot.Clear();
92 }
93 }
94 }
95 }
96 }
97 return false;
98 }
99
UpdateObjectSlot(ObjectSlot & slot)100 void ParallelEvacuator::UpdateObjectSlot(ObjectSlot &slot)
101 {
102 JSTaggedValue value(slot.GetTaggedType());
103 if (value.IsHeapObject()) {
104 if (value.IsWeakForHeapObject()) {
105 return UpdateWeakObjectSlot(value.GetTaggedWeakRef(), slot);
106 }
107 TaggedObject *object = value.GetTaggedObject();
108 MarkWord markWord(object);
109 if (markWord.IsForwardingAddress()) {
110 TaggedObject *dst = markWord.ToForwardingAddress();
111 slot.Update(dst);
112 }
113 }
114 }
115
UpdateWeakObjectSlot(TaggedObject * value,ObjectSlot & slot)116 void ParallelEvacuator::UpdateWeakObjectSlot(TaggedObject *value, ObjectSlot &slot)
117 {
118 Region *objectRegion = Region::ObjectAddressToRange(value);
119 if (objectRegion->InYoungSpaceOrCSet()) {
120 if (objectRegion->InNewToNewSet()) {
121 if (!objectRegion->Test(value)) {
122 slot.Clear();
123 }
124 } else {
125 MarkWord markWord(value);
126 if (markWord.IsForwardingAddress()) {
127 TaggedObject *dst = markWord.ToForwardingAddress();
128 auto weakRef = JSTaggedValue(dst).CreateAndGetWeakRef().GetRawTaggedObject();
129 slot.Update(weakRef);
130 return;
131 }
132 slot.Clear();
133 }
134 return;
135 }
136
137 if (heap_->IsFullMark()) {
138 if (!objectRegion->Test(value)) {
139 slot.Clear();
140 }
141 }
142 }
143
SetObjectFieldRSet(TaggedObject * object,JSHClass * cls)144 void ParallelEvacuator::SetObjectFieldRSet(TaggedObject *object, JSHClass *cls)
145 {
146 Region *region = Region::ObjectAddressToRange(object);
147 auto callbackWithCSet = [this, region](TaggedObject *root, ObjectSlot start, ObjectSlot end, VisitObjectArea area) {
148 if (area == VisitObjectArea::IN_OBJECT) {
149 if (VisitBodyInObj(root, start, end, [&](ObjectSlot slot) { SetObjectRSet(slot, region); })) {
150 return;
151 };
152 }
153 for (ObjectSlot slot = start; slot < end; slot++) {
154 SetObjectRSet(slot, region);
155 }
156 };
157 objXRay_.VisitObjectBody<VisitType::OLD_GC_VISIT>(object, cls, callbackWithCSet);
158 }
159
SetObjectRSet(ObjectSlot slot,Region * region)160 void ParallelEvacuator::SetObjectRSet(ObjectSlot slot, Region *region)
161 {
162 JSTaggedType value = slot.GetTaggedType();
163 if (!JSTaggedValue(value).IsHeapObject()) {
164 return;
165 }
166 Region *valueRegion = Region::ObjectAddressToRange(value);
167 if (valueRegion->InYoungSpace()) {
168 region->InsertOldToNewRSet(slot.SlotAddress());
169 } else if (valueRegion->InCollectSet() || JSTaggedValue(value).IsWeakForHeapObject()) {
170 region->InsertCrossRegionRSet(slot.SlotAddress());
171 }
172 }
173
GetWorkloadSafe()174 std::unique_ptr<ParallelEvacuator::Workload> ParallelEvacuator::GetWorkloadSafe()
175 {
176 os::memory::LockHolder holder(mutex_);
177 std::unique_ptr<Workload> unit;
178 if (!workloads_.empty()) {
179 unit = std::move(workloads_.back());
180 workloads_.pop_back();
181 }
182 return unit;
183 }
184
AddWorkload(std::unique_ptr<Workload> region)185 void ParallelEvacuator::AddWorkload(std::unique_ptr<Workload> region)
186 {
187 workloads_.emplace_back(std::move(region));
188 }
189
CalculateEvacuationThreadNum()190 int ParallelEvacuator::CalculateEvacuationThreadNum()
191 {
192 uint32_t length = workloads_.size();
193 uint32_t regionPerThread = 8;
194 uint32_t maxThreadNum = std::min(heap_->GetMaxEvacuateTaskCount(),
195 Taskpool::GetCurrentTaskpool()->GetTotalThreadNum());
196 return static_cast<int>(std::min(std::max(1U, length / regionPerThread), maxThreadNum));
197 }
198
CalculateUpdateThreadNum()199 int ParallelEvacuator::CalculateUpdateThreadNum()
200 {
201 uint32_t length = workloads_.size();
202 double regionPerThread = 1.0 / 4;
203 length = std::pow(length, regionPerThread);
204 uint32_t maxThreadNum = std::min(heap_->GetMaxEvacuateTaskCount(),
205 Taskpool::GetCurrentTaskpool()->GetTotalThreadNum());
206 return static_cast<int>(std::min(std::max(1U, length), maxThreadNum));
207 }
208 } // namespace panda::ecmascript
209 #endif // ECMASCRIPT_MEM_PARALLEL_EVACUATOR_INL_H
210