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
+35 -14
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) {
ContainerHeaderDeque toVisit;
toVisit.push_back(start);
while (!toVisit.empty()) {
auto container = toVisit.front();
toVisit.pop_front();
if (useColor) { if (useColor) {
if (container->color() == CONTAINER_TAG_GC_GRAY) return; if (container->color() == CONTAINER_TAG_GC_GRAY) continue;
} else { } else {
if (container->marked()) return; if (container->marked()) continue;
} }
if (useColor) { if (useColor) {
container->setColor(CONTAINER_TAG_GC_GRAY); container->setColor(CONTAINER_TAG_GC_GRAY);
} else { } else {
container->mark(); container->mark();
} }
traverseContainerReferredObjects(container, [](ObjHeader* ref) { traverseContainerReferredObjects(container, [&toVisit](ObjHeader* ref) {
auto childContainer = ref->container(); auto childContainer = ref->container();
RuntimeAssert(!isArena(childContainer), "A reference to local object is encountered"); RuntimeAssert(!isArena(childContainer), "A reference to local object is encountered");
if (!childContainer->permanentOrFrozen()) { if (!childContainer->permanentOrFrozen()) {
childContainer->decRefCount<false>(); childContainer->decRefCount<false>();
MarkGray<useColor>(childContainer); 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) {
ContainerHeaderDeque toVisit;
toVisit.push_back(start);
while (!toVisit.empty()) {
auto container = toVisit.front();
toVisit.pop_front();
if (useColor) { if (useColor) {
container->setColor(CONTAINER_TAG_GC_BLACK); container->setColor(CONTAINER_TAG_GC_BLACK);
} else { } else {
container->unMark(); container->unMark();
} }
traverseContainerReferredObjects(container, [](ObjHeader* ref) {
traverseContainerReferredObjects(container, [&toVisit](ObjHeader* ref) {
auto childContainer = ref->container(); auto childContainer = ref->container();
RuntimeAssert(!isArena(childContainer), "A reference to local object is encountered"); RuntimeAssert(!isArena(childContainer), "A reference to local object is encountered");
if (!childContainer->permanentOrFrozen()) { if (!childContainer->permanentOrFrozen()) {
childContainer->incRefCount<false>(); childContainer->incRefCount<false>();
if (useColor) { if (useColor) {
if (childContainer->color() != CONTAINER_TAG_GC_BLACK) if (childContainer->color() != CONTAINER_TAG_GC_BLACK)
ScanBlack<useColor>(childContainer); toVisit.push_front(childContainer);
} else { } else {
if (childContainer->marked()) if (childContainer->marked())
ScanBlack<useColor>(childContainer); toVisit.push_front(childContainer);
} }
} }
}); });
}
} }
void CollectWhite(MemoryState*, ContainerHeader* container); void CollectWhite(MemoryState*, ContainerHeader* container);
@@ -735,11 +750,16 @@ 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);
while (!toVisit.empty()) {
auto container = toVisit.front();
toVisit.pop_front();
if (container->color() != CONTAINER_TAG_GC_WHITE || container->buffered()) continue;
container->setColor(CONTAINER_TAG_GC_BLACK); container->setColor(CONTAINER_TAG_GC_BLACK);
traverseContainerObjectFields(container, [state](ObjHeader** location) { traverseContainerObjectFields(container, [state, &toVisit](ObjHeader** location) {
auto ref = *location; auto ref = *location;
if (ref == nullptr) return; if (ref == nullptr) return;
auto childContainer = ref->container(); auto childContainer = ref->container();
@@ -747,11 +767,12 @@ void CollectWhite(MemoryState* state, ContainerHeader* container) {
if (childContainer->permanentOrFrozen()) { if (childContainer->permanentOrFrozen()) {
UpdateRef(location, nullptr); UpdateRef(location, nullptr);
} else { } else {
CollectWhite(state, childContainer); toVisit.push_front(childContainer);
} }
}); });
runDeallocationHooks(container); runDeallocationHooks(container);
scheduleDestroyContainer(state, container); scheduleDestroyContainer(state, container);
}
} }
#endif #endif