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