• 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     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