• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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