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#include "ecmascript/mem/incremental_marker.h" 16#include "ecmascript/mem/parallel_marker-inl.h" 17 18namespace panda::ecmascript { 19Marker::Marker(Heap *heap) : heap_(heap), workManager_(heap->GetWorkManager()) {} 20 21void Marker::MarkRoots(uint32_t threadId, VMRootVisitType type) 22{ 23 TRACE_GC(GCStats::Scope::ScopeId::MarkRoots, heap_->GetEcmaVM()->GetEcmaGCStats()); 24 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "GC::MarkRoots"); 25 ObjectXRay::VisitVMRoots( 26 heap_->GetEcmaVM(), 27 [this, threadId](Root type, ObjectSlot slot) {this->HandleRoots(threadId, type, slot);}, 28 [this, threadId](Root type, ObjectSlot start, ObjectSlot end) { 29 this->HandleRangeRoots(threadId, type, start, end); 30 }, 31 [this](Root type, ObjectSlot base, ObjectSlot derived, uintptr_t baseOldObject) { 32 this->HandleDerivedRoots(type, base, derived, baseOldObject); 33 }, type); 34 workManager_->PushWorkNodeToGlobal(threadId, false); 35} 36 37void Marker::ProcessNewToEden(uint32_t threadId) 38{ 39 heap_->EnumerateNewSpaceRegions([this, threadId](Region *region) {this->HandleNewToEdenRSet(threadId, region);}); 40 ProcessMarkStack(threadId); 41} 42 43void Marker::ProcessNewToEdenNoMarkStack(uint32_t threadId) 44{ 45 heap_->EnumerateNewSpaceRegions([this, threadId](Region *region) {this->HandleNewToEdenRSet(threadId, region);}); 46} 47 48void Marker::ProcessOldToNew(uint32_t threadId) 49{ 50 heap_->EnumerateOldSpaceRegions([this, threadId](Region *region) { 51 this->HandleOldToNewRSet(threadId, region); 52 }); 53 ProcessMarkStack(threadId); 54} 55 56void Marker::ProcessOldToNewNoMarkStack(uint32_t threadId) 57{ 58 heap_->EnumerateOldSpaceRegions([this, threadId](Region *region) { 59 this->HandleOldToNewRSet(threadId, region); 60 }); 61} 62 63void Marker::ProcessOldToNew(uint32_t threadId, Region *region) 64{ 65 heap_->EnumerateOldSpaceRegions([this, threadId](Region *region) { 66 this->HandleOldToNewRSet(threadId, region); 67 }, region); 68 ProcessMarkStack(threadId); 69} 70 71void Marker::ProcessSnapshotRSet(uint32_t threadId) 72{ 73 heap_->EnumerateSnapshotSpaceRegions([this, threadId](Region *region) { 74 this->HandleOldToNewRSet(threadId, region); 75 }); 76 ProcessMarkStack(threadId); 77} 78 79void Marker::ProcessSnapshotRSetNoMarkStack(uint32_t threadId) 80{ 81 heap_->EnumerateSnapshotSpaceRegions([this, threadId](Region *region) { 82 this->HandleOldToNewRSet(threadId, region); 83 }); 84} 85 86void NonMovableMarker::MarkJitCodeMap(uint32_t threadId) 87{ 88 // To keep MachineCode objects alive (for dump) before JsError object be free, we have to know which JsError is 89 // alive first. So this method must be call after all other mark work finish. 90 TRACE_GC(GCStats::Scope::ScopeId::MarkRoots, heap_->GetEcmaVM()->GetEcmaGCStats()); 91 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "GC::MarkJitCodeMap"); 92 if (!heap_->IsFullMark()) { 93 return; 94 } 95 JitCodeMapVisitor visitor = [this, threadId](std::map<JSTaggedType, JitCodeVector *> &jitCodeMaps) { 96 auto it = jitCodeMaps.begin(); 97 while (it != jitCodeMaps.end()) { 98 JSTaggedType jsError = it->first; 99 Region *objectRegion = Region::ObjectAddressToRange(reinterpret_cast<TaggedObject *>(jsError)); 100 if (!objectRegion->Test(reinterpret_cast<TaggedObject *>(jsError))) { 101 ++it; 102 continue; 103 } 104 for (auto &jitCodeMap : *(it->second)) { 105 auto &jitCode = std::get<0>(jitCodeMap); 106 MarkObject(threadId, jitCode); 107 } 108 ++it; 109 } 110 }; 111 ObjectXRay::VisitJitCodeMap(heap_->GetEcmaVM(), visitor); 112 ProcessMarkStack(threadId); 113 heap_->WaitRunningTaskFinished(); 114} 115 116void NonMovableMarker::ProcessMarkStack(uint32_t threadId) 117{ 118 bool isFullMark = heap_->IsConcurrentFullMark(); 119 auto cb = [&](ObjectSlot s, Region *rootRegion, bool needBarrier) { 120 MarkValue(threadId, s, rootRegion, needBarrier); 121 }; 122 EcmaObjectRangeVisitor visitor = [this, threadId, isFullMark, cb](TaggedObject *root, ObjectSlot start, 123 ObjectSlot end, VisitObjectArea area) { 124 Region *rootRegion = Region::ObjectAddressToRange(root); 125 bool needBarrier = isFullMark && !rootRegion->InGeneralNewSpaceOrCSet(); 126 if (area == VisitObjectArea::IN_OBJECT) { 127 if (VisitBodyInObj(root, start, end, needBarrier, cb)) { 128 return; 129 } 130 } 131 for (ObjectSlot slot = start; slot < end; slot++) { 132 MarkValue(threadId, slot, rootRegion, needBarrier); 133 } 134 }; 135 SemiSpace *newSpace = heap_->GetNewSpace(); 136 TaggedObject *obj = nullptr; 137 while (workManager_->Pop(threadId, &obj)) { 138 Region *region = Region::ObjectAddressToRange(obj); 139 if (region->IsHalfFreshRegion()) { 140 ASSERT(region->InYoungSpace()); 141 if (newSpace->IsFreshObjectInHalfFreshRegion(obj)) { 142 // Fresh object do not need to visit body. 143 continue; 144 } 145 } 146 147 JSHClass *jsHclass = obj->SynchronizedGetClass(); 148 ASSERT(!region->IsFreshRegion()); 149 auto size = jsHclass->SizeFromJSHClass(obj); 150 region->IncreaseAliveObjectSafe(size); 151 MarkObject(threadId, jsHclass); 152 ObjectXRay::VisitObjectBody<VisitType::OLD_GC_VISIT>(obj, jsHclass, visitor); 153 } 154} 155 156void NonMovableMarker::ProcessIncrementalMarkStack(uint32_t threadId, uint32_t markStepSize) 157{ 158 bool isFullMark = heap_->IsConcurrentFullMark(); 159 uint32_t visitAddrNum = 0; 160 auto cb = [&](ObjectSlot s, Region *rootRegion, bool needBarrier) { 161 MarkValue(threadId, s, rootRegion, needBarrier); 162 }; 163 EcmaObjectRangeVisitor visitor = [this, threadId, isFullMark, &visitAddrNum, cb](TaggedObject *root, 164 ObjectSlot start, 165 ObjectSlot end, 166 VisitObjectArea area) { 167 Region *rootRegion = Region::ObjectAddressToRange(root); 168 visitAddrNum += end.SlotAddress() - start.SlotAddress(); 169 bool needBarrier = isFullMark && !rootRegion->InGeneralNewSpaceOrCSet(); 170 if (area == VisitObjectArea::IN_OBJECT) { 171 if (VisitBodyInObj(root, start, end, needBarrier, cb)) { 172 return; 173 } 174 } 175 for (ObjectSlot slot = start; slot < end; slot++) { 176 MarkValue(threadId, slot, rootRegion, needBarrier); 177 } 178 }; 179 TaggedObject *obj = nullptr; 180 double startTime = heap_->GetIncrementalMarker()->GetCurrentTimeInMs(); 181 double costTime = startTime; 182 while (workManager_->Pop(threadId, &obj)) { 183 JSHClass *jsHclass = obj->GetClass(); 184 Region *region = Region::ObjectAddressToRange(obj); 185 auto size = jsHclass->SizeFromJSHClass(obj); 186 region->IncreaseAliveObjectSafe(size); 187 MarkObject(threadId, jsHclass); 188 ObjectXRay::VisitObjectBody<VisitType::OLD_GC_VISIT>(obj, jsHclass, visitor); 189 if (heap_->GetIncrementalMarker()->IsTriggeredIncrementalMark() && visitAddrNum >= markStepSize) { 190 costTime = heap_->GetIncrementalMarker()->GetCurrentTimeInMs() - startTime; 191 heap_->GetIncrementalMarker()->UpdateMarkingSpeed(visitAddrNum, costTime); 192 return; 193 } 194 } 195 if (heap_->GetJSThread()->IsMarking() && heap_->GetIncrementalMarker()->IsTriggeredIncrementalMark()) { 196 costTime = heap_->GetIncrementalMarker()->GetCurrentTimeInMs() - startTime; 197 heap_->GetIncrementalMarker()->UpdateMarkingSpeed(visitAddrNum, costTime); 198 heap_->GetIncrementalMarker()->SetMarkingFinished(true); 199 } 200} 201 202void SemiGCMarker::Initialize() 203{ 204 waterLine_ = heap_->GetNewSpace()->GetWaterLine(); 205} 206 207void SemiGCMarker::ProcessMarkStack(uint32_t threadId) 208{ 209 auto cb = [&](ObjectSlot s, TaggedObject *root) { MarkValue(threadId, root, s); }; 210 EcmaObjectRangeVisitor visitor = [this, threadId, cb](TaggedObject *root, ObjectSlot start, 211 ObjectSlot end, VisitObjectArea area) { 212 if (area == VisitObjectArea::IN_OBJECT) { 213 if (VisitBodyInObj(root, start, end, cb)) { 214 return; 215 } 216 } 217 for (ObjectSlot slot = start; slot < end; slot++) { 218 MarkValue(threadId, root, slot); 219 } 220 }; 221 TaggedObject *obj = nullptr; 222 while (workManager_->Pop(threadId, &obj)) { 223 auto jsHclass = obj->GetClass(); 224 ObjectXRay::VisitObjectBody<VisitType::SEMI_GC_VISIT>(obj, jsHclass, visitor); 225 } 226} 227 228void CompressGCMarker::ProcessMarkStack(uint32_t threadId) 229{ 230 auto cb = [&](ObjectSlot s, [[maybe_unused]] TaggedObject *root) { MarkValue(threadId, s); }; 231 EcmaObjectRangeVisitor visitor = [this, threadId, cb](TaggedObject *root, ObjectSlot start, 232 ObjectSlot end, VisitObjectArea area) { 233 if (area == VisitObjectArea::IN_OBJECT) { 234 if (VisitBodyInObj(root, start, end, cb)) { 235 return; 236 } 237 } 238 for (ObjectSlot slot = start; slot < end; slot++) { 239 MarkValue(threadId, slot); 240 } 241 }; 242 TaggedObject *obj = nullptr; 243 while (workManager_->Pop(threadId, &obj)) { 244 auto jsHClass = obj->GetClass(); 245 ObjectSlot objectSlot(ToUintPtr(obj)); 246 MarkObject(threadId, jsHClass, objectSlot); 247 ObjectXRay::VisitObjectBody<VisitType::OLD_GC_VISIT>(obj, jsHClass, visitor); 248 } 249} 250 251void CompressGCMarker::MarkJitCodeMap(uint32_t threadId) 252{ 253 // To keep MachineCode objects alive (for dump) before JsError object be free, we have to know which JsError is 254 // alive first. So this method must be call after all other mark work finish. 255 TRACE_GC(GCStats::Scope::ScopeId::MarkRoots, heap_->GetEcmaVM()->GetEcmaGCStats()); 256 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "GC::MarkJitCodeMap"); 257 ObjectXRay::VisitJitCodeMap(heap_->GetEcmaVM(), 258 [this, threadId](std::map<JSTaggedType, JitCodeVector *> &jitCodeMaps) { 259 this->HandleVisitJitCodeMap(threadId, jitCodeMaps); 260 }); 261 ProcessMarkStack(threadId); 262 heap_->WaitRunningTaskFinished(); 263} 264 265void CompressGCMarker::HandleVisitJitCodeMap(uint32_t threadId, std::map<JSTaggedType, JitCodeVector *> &jitCodeMaps) 266{ 267 auto it = jitCodeMaps.begin(); 268 while (it != jitCodeMaps.end()) { 269 JSTaggedType jsError = it->first; 270 auto jsErrorObj = reinterpret_cast<TaggedObject *>(jsError); 271 Region *objectRegion = Region::ObjectAddressToRange(jsErrorObj); 272 auto jitCodeVec = it->second; 273 if (!NeedEvacuate(objectRegion)) { 274 if (!objectRegion->InSharedHeap() && !objectRegion->Test(jsErrorObj)) { 275 delete it->second; 276 it = jitCodeMaps.erase(it); 277 continue; 278 } 279 } else { 280 MarkWord markWord(jsErrorObj); 281 if (markWord.IsForwardingAddress()) { 282 TaggedObject *dst = markWord.ToForwardingAddress(); 283 jitCodeMaps.emplace(JSTaggedValue(dst).GetRawData(), it->second); 284 it = jitCodeMaps.erase(it); 285 } else { 286 delete it->second; 287 it = jitCodeMaps.erase(it); 288 continue; 289 } 290 } 291 for (auto &jitCodeMap : *jitCodeVec) { 292 auto &jitCode = std::get<0>(jitCodeMap); 293 auto obj = static_cast<TaggedObject *>(jitCode); 294 // jitcode is MachineCode, and MachineCode is in the MachineCode space, will not be evacute. 295 MarkObject(threadId, obj, ObjectSlot(reinterpret_cast<uintptr_t>(&jitCode))); 296 } 297 ++it; 298 } 299} 300 301uintptr_t CompressGCMarker::AllocateForwardAddress(uint32_t threadId, size_t size, JSHClass *hclass, 302 TaggedObject *object) 303{ 304 if (!isAppSpawn_) { 305 bool isPromoted = true; 306 return AllocateDstSpace(threadId, size, isPromoted); 307 } 308 if (Heap::ShouldMoveToRoSpace(hclass, object)) { 309 return AllocateReadOnlySpace(size); 310 } else { 311 return AllocateAppSpawnSpace(size); 312 } 313} 314} // namespace panda::ecmascript 315