Avoid recursion in GC traversals. (#2322)
This commit is contained in:
@@ -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
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user