Avoid recursion in GC traversals. (#2322)

This commit is contained in:
Nikolay Igotti
2018-11-14 18:50:22 +03:00
committed by GitHub
parent cd7a377e8f
commit 2a65528968
+75 -54
View File
@@ -627,51 +627,66 @@ void ScanRoots(MemoryState*);
void CollectRoots(MemoryState*); void CollectRoots(MemoryState*);
template<bool useColor> template<bool useColor>
void MarkGray(ContainerHeader* container) { void MarkGray(ContainerHeader* start) {
if (useColor) { ContainerHeaderDeque toVisit;
if (container->color() == CONTAINER_TAG_GC_GRAY) return; toVisit.push_back(start);
} else {
if (container->marked()) return;
}
if (useColor) {
container->setColor(CONTAINER_TAG_GC_GRAY);
} else {
container->mark();
}
traverseContainerReferredObjects(container, [](ObjHeader* ref) {
auto childContainer = ref->container();
RuntimeAssert(!isArena(childContainer), "A reference to local object is encountered");
if (!childContainer->permanentOrFrozen()) { while (!toVisit.empty()) {
childContainer->decRefCount<false>(); auto container = toVisit.front();
MarkGray<useColor>(childContainer); toVisit.pop_front();
if (useColor) {
if (container->color() == CONTAINER_TAG_GC_GRAY) continue;
} else {
if (container->marked()) continue;
} }
}); if (useColor) {
container->setColor(CONTAINER_TAG_GC_GRAY);
} else {
container->mark();
}
traverseContainerReferredObjects(container, [&toVisit](ObjHeader* ref) {
auto childContainer = ref->container();
RuntimeAssert(!isArena(childContainer), "A reference to local object is encountered");
if (!childContainer->permanentOrFrozen()) {
childContainer->decRefCount<false>();
toVisit.push_front(childContainer);
}
});
}
} }
void Scan(ContainerHeader* container); void Scan(ContainerHeader* container);
template<bool useColor> template<bool useColor>
void ScanBlack(ContainerHeader* container) { void ScanBlack(ContainerHeader* start) {
if (useColor) { ContainerHeaderDeque toVisit;
container->setColor(CONTAINER_TAG_GC_BLACK); toVisit.push_back(start);
} else {
container->unMark(); while (!toVisit.empty()) {
} auto container = toVisit.front();
traverseContainerReferredObjects(container, [](ObjHeader* ref) { toVisit.pop_front();
auto childContainer = ref->container(); if (useColor) {
RuntimeAssert(!isArena(childContainer), "A reference to local object is encountered"); container->setColor(CONTAINER_TAG_GC_BLACK);
if (!childContainer->permanentOrFrozen()) { } else {
childContainer->incRefCount<false>(); container->unMark();
if (useColor) {
if (childContainer->color() != CONTAINER_TAG_GC_BLACK)
ScanBlack<useColor>(childContainer);
} else {
if (childContainer->marked())
ScanBlack<useColor>(childContainer);
}
} }
});
traverseContainerReferredObjects(container, [&toVisit](ObjHeader* ref) {
auto childContainer = ref->container();
RuntimeAssert(!isArena(childContainer), "A reference to local object is encountered");
if (!childContainer->permanentOrFrozen()) {
childContainer->incRefCount<false>();
if (useColor) {
if (childContainer->color() != CONTAINER_TAG_GC_BLACK)
toVisit.push_front(childContainer);
} else {
if (childContainer->marked())
toVisit.push_front(childContainer);
}
}
});
}
} }
void CollectWhite(MemoryState*, ContainerHeader* container); void CollectWhite(MemoryState*, ContainerHeader* container);
@@ -735,23 +750,29 @@ void Scan(ContainerHeader* container) {
}); });
} }
void CollectWhite(MemoryState* state, ContainerHeader* container) { void CollectWhite(MemoryState* state, ContainerHeader* start) {
if (container->color() != CONTAINER_TAG_GC_WHITE || container->buffered()) ContainerHeaderDeque toVisit;
return; toVisit.push_back(start);
container->setColor(CONTAINER_TAG_GC_BLACK);
traverseContainerObjectFields(container, [state](ObjHeader** location) { while (!toVisit.empty()) {
auto ref = *location; auto container = toVisit.front();
if (ref == nullptr) return; toVisit.pop_front();
auto childContainer = ref->container(); if (container->color() != CONTAINER_TAG_GC_WHITE || container->buffered()) continue;
RuntimeAssert(!isArena(childContainer), "A reference to local object is encountered"); container->setColor(CONTAINER_TAG_GC_BLACK);
if (childContainer->permanentOrFrozen()) { traverseContainerObjectFields(container, [state, &toVisit](ObjHeader** location) {
UpdateRef(location, nullptr); auto ref = *location;
} else { if (ref == nullptr) return;
CollectWhite(state, childContainer); auto childContainer = ref->container();
} RuntimeAssert(!isArena(childContainer), "A reference to local object is encountered");
}); if (childContainer->permanentOrFrozen()) {
runDeallocationHooks(container); UpdateRef(location, nullptr);
scheduleDestroyContainer(state, container); } else {
toVisit.push_front(childContainer);
}
});
runDeallocationHooks(container);
scheduleDestroyContainer(state, container);
}
} }
#endif #endif