Replace finalization queue with the linked list.

This commit is contained in:
Nikolay Igotti
2018-11-23 11:13:44 +03:00
committed by Nikolay Igotti
parent cedcd2cf79
commit 58a82b22bb
2 changed files with 26 additions and 30 deletions
+17 -30
View File
@@ -134,21 +134,6 @@ public:
void incAlloc(size_t size, const ContainerHeader* header) { void incAlloc(size_t size, const ContainerHeader* header) {
containerAllocs[toIndex(header)][0]++; containerAllocs[toIndex(header)][0]++;
++(*allocationHistogram)[size]; ++(*allocationHistogram)[size];
#if 0
auto queue = memoryState->finalizerQueue;
bool hit = false;
for (int i = 0; i < queue->size(); i++) {
auto container = (*queue)[i];
if (containerSize(container) == size) {
hit = true;
break;
}
}
if (hit)
allocCacheHit++;
else
allocCacheMiss++;
#endif // USE_GC
} }
void incFree(const ContainerHeader* header) { void incFree(const ContainerHeader* header) {
@@ -230,9 +215,10 @@ struct MemoryState {
#endif #endif
#if USE_GC #if USE_GC
// Finalizer queue. // Finalizer queue - linked list of containers scheduled for finalization.
ContainerHeaderDeque* finalizerQueue; ContainerHeader* finalizerQueue;
int finalizerQueueSize;
int finalizerQueueSuspendCount;
/* /*
* Typical scenario for GC is as following: * Typical scenario for GC is as following:
* we have 90% of objects with refcount = 0 which will be deleted during * we have 90% of objects with refcount = 0 which will be deleted during
@@ -249,7 +235,6 @@ struct MemoryState {
size_t gcThreshold; size_t gcThreshold;
// If collection is in progress. // If collection is in progress.
bool gcInProgress; bool gcInProgress;
int finalizerQueueSuspendCount;
#if GC_ERGONOMICS #if GC_ERGONOMICS
uint64_t lastGcTimestamp; uint64_t lastGcTimestamp;
@@ -509,9 +494,10 @@ inline ContainerHeader* markAsRemoved(ContainerHeader* container) {
inline void processFinalizerQueue(MemoryState* state) { inline void processFinalizerQueue(MemoryState* state) {
// TODO: reuse elements of finalizer queue for new allocations. // TODO: reuse elements of finalizer queue for new allocations.
while (!state->finalizerQueue->empty()) { while (state->finalizerQueue != nullptr) {
auto container = memoryState->finalizerQueue->back(); auto* container = state->finalizerQueue;
state->finalizerQueue->pop_back(); state->finalizerQueue = container->nextLink();
state->finalizerQueueSize--;
#if TRACE_MEMORY #if TRACE_MEMORY
state->containers->erase(container); state->containers->erase(container);
#endif #endif
@@ -519,15 +505,18 @@ inline void processFinalizerQueue(MemoryState* state) {
konanFreeMemory(container); konanFreeMemory(container);
atomicAdd(&allocCount, -1); atomicAdd(&allocCount, -1);
} }
RuntimeAssert(state->finalizerQueueSize == 0, "Queue must be empty here");
} }
#endif #endif
inline void scheduleDestroyContainer( inline void scheduleDestroyContainer(MemoryState* state, ContainerHeader* container) {
MemoryState* state, ContainerHeader* container) {
#if USE_GC #if USE_GC
state->finalizerQueue->push_front(container); RuntimeAssert(container != nullptr, "Cannot destroy null container");
container->setNextLink(state->finalizerQueue);
state->finalizerQueue = container;
state->finalizerQueueSize++;
// We cannot clean finalizer queue while in GC. // We cannot clean finalizer queue while in GC.
if (!state->gcInProgress && state->finalizerQueueSuspendCount == 0 && state->finalizerQueue->size() > 256) { if (!state->gcInProgress && state->finalizerQueueSuspendCount == 0 && state->finalizerQueueSize > 256) {
processFinalizerQueue(state); processFinalizerQueue(state);
} }
#else #else
@@ -537,7 +526,6 @@ inline void scheduleDestroyContainer(
#endif #endif
} }
#if !USE_GC #if !USE_GC
template <bool Atomic> template <bool Atomic>
@@ -1137,7 +1125,6 @@ MemoryState* InitMemory() {
memoryState = konanConstructInstance<MemoryState>(); memoryState = konanConstructInstance<MemoryState>();
INIT_EVENT(memoryState) INIT_EVENT(memoryState)
#if USE_GC #if USE_GC
memoryState->finalizerQueue = konanConstructInstance<ContainerHeaderDeque>();
memoryState->toFree = konanConstructInstance<ContainerHeaderList>(); memoryState->toFree = konanConstructInstance<ContainerHeaderList>();
memoryState->roots = konanConstructInstance<ContainerHeaderList>(); memoryState->roots = konanConstructInstance<ContainerHeaderList>();
memoryState->gcInProgress = false; memoryState->gcInProgress = false;
@@ -1155,8 +1142,8 @@ void DeinitMemory(MemoryState* memoryState) {
konanDestructInstance(memoryState->toFree); konanDestructInstance(memoryState->toFree);
konanDestructInstance(memoryState->roots); konanDestructInstance(memoryState->roots);
konanDestructInstance(memoryState->finalizerQueue); RuntimeAssert(memoryState->finalizerQueue == nullptr, "Finalizer queue must be empty");
memoryState->finalizerQueue = nullptr; RuntimeAssert(memoryState->finalizerQueueSize == 0, "Finalizer queue must be empty");
#endif // USE_GC #endif // USE_GC
+9
View File
@@ -217,6 +217,15 @@ struct ContainerHeader {
inline void resetSeen() { inline void resetSeen() {
objectCount_ &= ~CONTAINER_TAG_GC_SEEN; objectCount_ &= ~CONTAINER_TAG_GC_SEEN;
} }
// We cannot use 'this' here, as it conflicts with aliasing analysis in clang.
inline void setNextLink(ContainerHeader* next) {
*reinterpret_cast<ContainerHeader**>(this + 1) = next;
}
inline ContainerHeader* nextLink() {
return *reinterpret_cast<ContainerHeader**>(this + 1);
}
}; };
struct ArrayHeader; struct ArrayHeader;