1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-15 23:12:44 +01:00

Checkpoint

This commit is contained in:
Eelco Dolstra 2019-04-22 23:25:47 +02:00
parent 4237414f4d
commit 7c716b4c49
27 changed files with 596 additions and 440 deletions

View file

@ -18,6 +18,15 @@ GC::GC()
backSentinel->prev = frontSentinel;
backSentinel->next = nullptr;
frontRootSentinel = (Root<Object> *) malloc(sizeof(Root<Object>));
backRootSentinel = (Root<Object> *) malloc(sizeof(Root<Object>));
frontRootSentinel->prev = nullptr;
frontRootSentinel->next = backRootSentinel;
backRootSentinel->prev = frontRootSentinel;
backRootSentinel->next = nullptr;
}
GC::~GC()
@ -26,9 +35,18 @@ GC::~GC()
for (Ptr<Object> * p = frontSentinel->next; p != backSentinel; p = p->next)
n++;
if (n)
warn("%d GC roots still exist on exit", n);
warn("%d GC root pointers still exist on exit", n);
n = 0;
for (Root<Object> * p = frontRootSentinel->next; p != backRootSentinel; p = p->next)
n++;
if (n)
warn("%d GC root objects still exist on exit", n);
assert(!frontSentinel->prev);
assert(!backSentinel->next);
assert(!frontRootSentinel->prev);
assert(!backRootSentinel->next);
}
void GC::gc()
@ -37,112 +55,120 @@ void GC::gc()
std::stack<Object *> stack;
for (Ptr<Object> * p = frontSentinel->next; p != backSentinel; p = p->next) {
if (!p->value) continue;
// FIXME: ensure this gets inlined.
auto push = [&](Object * p) { if (p) { assertObject(p); stack.push(p); } };
stack.push(p->value);
auto pushPointers = [&](Object * obj) {
switch (obj->type) {
case tFree:
printError("reached a freed object at %x", obj);
abort();
case tBindings: {
auto obj2 = (Bindings *) obj;
for (auto i = obj2->attrs; i < obj2->attrs + obj2->size_; ++i)
push(i->value);
break;
}
case tValueList: {
auto obj2 = (PtrList<Object> *) obj;
for (auto i = obj2->elems; i < obj2->elems + obj2->size(); ++i)
push(*i);
break;
}
case tEnv: {
auto obj2 = (Env *) obj;
push(obj2->up);
if (obj2->type != Env::HasWithExpr)
for (auto i = obj2->values; i < obj2->values + obj2->size; ++i)
push(*i);
break;
}
case tInt:
case tBool:
case tNull:
case tList0:
case tFloat:
break;
case tString:
// FIXME
break;
case tPath:
// FIXME
break;
case tAttrs:
push(((Value *) obj)->attrs);
break;
case tList1:
push(((Value *) obj)->smallList[0]);
break;
case tList2:
push(((Value *) obj)->smallList[0]);
push(((Value *) obj)->smallList[1]);
break;
case tListN:
push(((Value *) obj)->bigList);
break;
case tThunk:
case tBlackhole:
push(((Value *) obj)->thunk.env);
break;
case tApp:
case tPrimOpApp:
push(((Value *) obj)->app.left);
push(((Value *) obj)->app.right);
break;
case tLambda:
push(((Value *) obj)->lambda.env);
break;
case tPrimOp:
// FIXME: GC primops?
break;
default:
printError("don't know how to traverse object at %x (tag %d)", obj, obj->type);
abort();
}
};
auto processStack = [&]() {
while (!stack.empty()) {
auto obj = stack.top();
stack.pop();
// FIXME: ensure this gets inlined.
auto push = [&](Object * p) { if (p) { /* FIXME */ assert(isObject(p)); stack.push(p); } };
//printError("MARK %x", obj);
if (!obj->isMarked()) {
marked++;
obj->mark();
switch (obj->type) {
case tFree:
printError("reached a freed object at %x", obj);
abort();
case tBindings: {
auto obj2 = (Bindings *) obj;
for (auto i = obj2->attrs; i < obj2->attrs + obj2->size_; ++i)
push(i->value);
break;
}
case tValueList: {
auto obj2 = (PtrList<Object> *) obj;
for (auto i = obj2->elems; i < obj2->elems + obj2->size(); ++i)
push(*i);
break;
}
case tEnv: {
auto obj2 = (Env *) obj;
push(obj2->up);
if (obj2->type != Env::HasWithExpr)
for (auto i = obj2->values; i < obj2->values + obj2->size; ++i)
push(*i);
break;
}
case tInt:
case tBool:
case tNull:
case tList0:
case tFloat:
break;
case tString:
// FIXME
break;
case tPath:
// FIXME
break;
case tAttrs:
push(((Value *) obj)->attrs);
break;
case tList1:
push(((Value *) obj)->smallList[0]);
break;
case tList2:
push(((Value *) obj)->smallList[0]);
push(((Value *) obj)->smallList[1]);
break;
case tListN:
push(((Value *) obj)->bigList);
break;
case tThunk:
push(((Value *) obj)->thunk.env);
break;
case tApp:
case tPrimOpApp:
push(((Value *) obj)->app.left);
push(((Value *) obj)->app.right);
break;
case tLambda:
push(((Value *) obj)->lambda.env);
break;
case tBlackhole:
// FIXME
break;
case tPrimOp:
// FIXME: GC primops?
break;
default:
printError("don't know how to traverse object at %x (tag %d)", obj, obj->type);
abort();
}
pushPointers(obj);
}
}
};
for (Root<Object> * p = frontRootSentinel->next; p != backRootSentinel; p = p->next) {
pushPointers(&p->value);
processStack();
}
for (Ptr<Object> * p = frontSentinel->next; p != backSentinel; p = p->next) {
if (!p->value) continue;
stack.push(p->value);
processStack();
}
Size totalObjectsFreed = 0;
@ -162,7 +188,7 @@ void GC::gc()
});
}
printError("freed %d bytes in %d dead objects, keeping %d objects",
debug("freed %d bytes in %d dead objects, keeping %d objects",
totalWordsFreed * WORD_SIZE, totalObjectsFreed, marked);
}
@ -224,6 +250,7 @@ std::pair<Size, Size> GC::Arena::freeUnmarked()
};
if (tag == tFree) {
//debug("FREE %x %d", obj, obj->getMisc());
if (curFree) {
// Merge this object into the previous free
// object.
@ -239,10 +266,13 @@ std::pair<Size, Size> GC::Arena::freeUnmarked()
if (obj->isMarked()) {
// Unmark to prepare for the next GC run.
//debug("KEEP OBJECT %x %d %d", obj, obj->type, objSize);
curFree = nullptr;
obj->unmark();
} else {
//printError("FREE %x %d %d", obj, obj->type, objSize);
//debug("FREE OBJECT %x %d %d", obj, obj->type, objSize);
for (Size i = 0; i < objSize; ++i)
((Word *) obj)[i] = 0xdeadc0dedeadbeefULL;
objectsFreed += 1;
wordsFreed += objSize;
if (curFree) {
@ -279,9 +309,18 @@ bool GC::isObject(void * p)
return false;
}
GC::ArenaList::ArenaList()
: nextSize(1024)
void GC::assertObject(void * p)
{
if (!isObject(p)) {
printError("object %p is not an object", p);
abort();
}
}
GC::ArenaList::ArenaList()
{
static Size initialHeapSize = std::stol(getEnv("GC_INITIAL_HEAP_SIZE", "1000000")) / WORD_SIZE;
nextSize = initialHeapSize;
}
}