diff options
-rw-r--r-- | rts/sm/NonMovingMark.c | 26 | ||||
-rw-r--r-- | rts/sm/NonMovingMark.h | 25 |
2 files changed, 38 insertions, 13 deletions
diff --git a/rts/sm/NonMovingMark.c b/rts/sm/NonMovingMark.c index 16693a710f..275cfcdd51 100644 --- a/rts/sm/NonMovingMark.c +++ b/rts/sm/NonMovingMark.c @@ -401,7 +401,6 @@ markQueuePushClosureGC (MarkQueue *q, StgClosure *p) } MarkQueueEnt ent = { - .type = MARK_CLOSURE, .mark_closure = { .p = UNTAG_CLOSURE(p), .origin = NULL, @@ -430,8 +429,12 @@ void push_closure (MarkQueue *q, // } #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 = { - .type = MARK_CLOSURE, .mark_closure = { .p = UNTAG_CLOSURE(p), .origin = origin, @@ -450,10 +453,9 @@ void push_array (MarkQueue *q, return; MarkQueueEnt ent = { - .type = MARK_ARRAY, .mark_array = { .array = array, - .start_index = start_index + .start_index = (start_index << 16) | 0x3, } }; push(q, &ent); @@ -716,7 +718,7 @@ again: // Is this the first block of the queue? if (q->blocks->link == NULL) { // Yes, therefore queue is empty... - MarkQueueEnt none = { .type = NULL_ENTRY }; + MarkQueueEnt none = { .null_entry = { .p = NULL } }; return none; } else { // No, unwind to the previous block and try popping again... @@ -1492,13 +1494,13 @@ nonmovingMark (MarkQueue *queue) count++; MarkQueueEnt ent = markQueuePop(queue); - switch (ent.type) { + switch (nonmovingMarkQueueEntryType(&ent)) { case MARK_CLOSURE: mark_closure(queue, ent.mark_closure.p, ent.mark_closure.origin); break; case MARK_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; if (end < arr->ptrs) { markQueuePushArray(queue, ent.mark_array.array, end); @@ -1743,13 +1745,17 @@ void nonmovingResurrectThreads (struct MarkQueue_ *queue, StgTSO **resurrected_t void printMarkQueueEntry (MarkQueueEnt *ent) { - if (ent->type == MARK_CLOSURE) { + switch(nonmovingMarkQueueEntryType(ent)) { + case MARK_CLOSURE: debugBelch("Closure: "); printClosure(ent->mark_closure.p); - } else if (ent->type == MARK_ARRAY) { + break; + case MARK_ARRAY: debugBelch("Array\n"); - } else { + break; + case NULL_ENTRY: debugBelch("End of mark\n"); + break; } } diff --git a/rts/sm/NonMovingMark.h b/rts/sm/NonMovingMark.h index a3629a2e99..bff89d9e92 100644 --- a/rts/sm/NonMovingMark.h +++ b/rts/sm/NonMovingMark.h @@ -43,21 +43,40 @@ enum EntryType { */ typedef struct { - enum EntryType type; - // All pointers should be untagged + // Which kind of mark queue entry we have is determined by the low bits of + // 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 { struct { + void *p; // must be NULL + } null_entry; + struct { StgClosure *p; // the object to be marked StgClosure **origin; // field where this reference was found. // See Note [Origin references in the nonmoving collector] } mark_closure; struct { const StgMutArrPtrs *array; - StgWord start_index; + StgWord start_index; // start index is shifted to the left by 16 bits } mark_array; }; } 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 { // index of first *unused* queue entry uint32_t head; |