Commit 3c8ad7e0 authored by Ben Gamari's avatar Ben Gamari 🐢

NonMovingMark: Optimize representation of mark queue

This shortens MarkQueueEntry by 30% (one word)
parent eb465927
...@@ -401,7 +401,6 @@ markQueuePushClosureGC (MarkQueue *q, StgClosure *p) ...@@ -401,7 +401,6 @@ markQueuePushClosureGC (MarkQueue *q, StgClosure *p)
} }
MarkQueueEnt ent = { MarkQueueEnt ent = {
.type = MARK_CLOSURE,
.mark_closure = { .mark_closure = {
.p = UNTAG_CLOSURE(p), .p = UNTAG_CLOSURE(p),
.origin = NULL, .origin = NULL,
...@@ -430,8 +429,12 @@ void push_closure (MarkQueue *q, ...@@ -430,8 +429,12 @@ void push_closure (MarkQueue *q,
// } // }
#endif #endif
// This must be true as origin points to a pointer and therefore must be
// word-aligned. However, we check this as otherwise we would confuse this
// with a mark_array entry
ASSERT(((uintptr_t) origin & 0x3) == 0);
MarkQueueEnt ent = { MarkQueueEnt ent = {
.type = MARK_CLOSURE,
.mark_closure = { .mark_closure = {
.p = UNTAG_CLOSURE(p), .p = UNTAG_CLOSURE(p),
.origin = origin, .origin = origin,
...@@ -450,10 +453,9 @@ void push_array (MarkQueue *q, ...@@ -450,10 +453,9 @@ void push_array (MarkQueue *q,
return; return;
MarkQueueEnt ent = { MarkQueueEnt ent = {
.type = MARK_ARRAY,
.mark_array = { .mark_array = {
.array = array, .array = array,
.start_index = start_index .start_index = (start_index << 16) | 0x3,
} }
}; };
push(q, &ent); push(q, &ent);
...@@ -716,7 +718,7 @@ again: ...@@ -716,7 +718,7 @@ again:
// Is this the first block of the queue? // Is this the first block of the queue?
if (q->blocks->link == NULL) { if (q->blocks->link == NULL) {
// Yes, therefore queue is empty... // Yes, therefore queue is empty...
MarkQueueEnt none = { .type = NULL_ENTRY }; MarkQueueEnt none = { .null_entry = { .p = NULL } };
return none; return none;
} else { } else {
// No, unwind to the previous block and try popping again... // No, unwind to the previous block and try popping again...
...@@ -1492,13 +1494,13 @@ nonmovingMark (MarkQueue *queue) ...@@ -1492,13 +1494,13 @@ nonmovingMark (MarkQueue *queue)
count++; count++;
MarkQueueEnt ent = markQueuePop(queue); MarkQueueEnt ent = markQueuePop(queue);
switch (ent.type) { switch (nonmovingMarkQueueEntryType(&ent)) {
case MARK_CLOSURE: case MARK_CLOSURE:
mark_closure(queue, ent.mark_closure.p, ent.mark_closure.origin); mark_closure(queue, ent.mark_closure.p, ent.mark_closure.origin);
break; break;
case MARK_ARRAY: { case MARK_ARRAY: {
const StgMutArrPtrs *arr = ent.mark_array.array; const StgMutArrPtrs *arr = ent.mark_array.array;
StgWord start = ent.mark_array.start_index; StgWord start = ent.mark_array.start_index >> 16;
StgWord end = start + MARK_ARRAY_CHUNK_LENGTH; StgWord end = start + MARK_ARRAY_CHUNK_LENGTH;
if (end < arr->ptrs) { if (end < arr->ptrs) {
markQueuePushArray(queue, ent.mark_array.array, end); markQueuePushArray(queue, ent.mark_array.array, end);
...@@ -1743,13 +1745,17 @@ void nonmovingResurrectThreads (struct MarkQueue_ *queue, StgTSO **resurrected_t ...@@ -1743,13 +1745,17 @@ void nonmovingResurrectThreads (struct MarkQueue_ *queue, StgTSO **resurrected_t
void printMarkQueueEntry (MarkQueueEnt *ent) void printMarkQueueEntry (MarkQueueEnt *ent)
{ {
if (ent->type == MARK_CLOSURE) { switch(nonmovingMarkQueueEntryType(ent)) {
case MARK_CLOSURE:
debugBelch("Closure: "); debugBelch("Closure: ");
printClosure(ent->mark_closure.p); printClosure(ent->mark_closure.p);
} else if (ent->type == MARK_ARRAY) { break;
case MARK_ARRAY:
debugBelch("Array\n"); debugBelch("Array\n");
} else { break;
case NULL_ENTRY:
debugBelch("End of mark\n"); debugBelch("End of mark\n");
break;
} }
} }
......
...@@ -43,9 +43,16 @@ enum EntryType { ...@@ -43,9 +43,16 @@ enum EntryType {
*/ */
typedef struct { typedef struct {
enum EntryType type; // Which kind of mark queue entry we have is determined by the low bits of
// All pointers should be untagged // the second word: they must be zero in the case of a mark_closure entry
// (since the second word of a mark_closure entry points to a pointer and
// pointers must be word-aligned). In the case of a mark_array we set them
// to 0x3 (the value of start_index is shifted to the left to accomodate
// this). null_entry where p==NULL is used to indicate the end of the queue.
union { union {
struct {
void *p; // must be NULL
} null_entry;
struct { struct {
StgClosure *p; // the object to be marked StgClosure *p; // the object to be marked
StgClosure **origin; // field where this reference was found. StgClosure **origin; // field where this reference was found.
...@@ -53,11 +60,23 @@ typedef struct { ...@@ -53,11 +60,23 @@ typedef struct {
} mark_closure; } mark_closure;
struct { struct {
const StgMutArrPtrs *array; const StgMutArrPtrs *array;
StgWord start_index; StgWord start_index; // start index is shifted to the left by 16 bits
} mark_array; } mark_array;
}; };
} MarkQueueEnt; } MarkQueueEnt;
INLINE_HEADER enum EntryType nonmovingMarkQueueEntryType(MarkQueueEnt *ent)
{
if (ent->null_entry.p == NULL) {
return NULL_ENTRY;
} else if (((uintptr_t) ent->mark_closure.origin & TAG_BITS) == 0) {
return MARK_CLOSURE;
} else {
ASSERT((ent->mark_array.start_index & TAG_BITS) == 0x3);
return MARK_ARRAY;
}
}
typedef struct { typedef struct {
// index of first *unused* queue entry // index of first *unused* queue entry
uint32_t head; uint32_t head;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment