Example #1
0
/* Some objects, having been copied, need no further attention. Others
 * need to do some additional freeing, however. This goes through the
 * fromspace and does any needed work to free uncopied things (this may
 * run in parallel with the mutator, which will be operating on tospace). */
void MVM_gc_collect_free_nursery_uncopied(MVMThreadContext *tc, void *limit) {
    /* We start scanning the fromspace, and keep going until we hit
     * the end of the area allocated in it. */
    void *scan = tc->nursery_fromspace;
    while (scan < limit) {
        /* The object here is dead if it never got a forwarding pointer
         * written in to it. */
        MVMCollectable *item = (MVMCollectable *)scan;
        MVMuint8 dead = item->forwarder == NULL;

        /* Now go by collectable type. */
        if (!(item->flags & (MVM_CF_TYPE_OBJECT | MVM_CF_STABLE))) {
            /* Object instance. If dead, call gc_free if needed. Scan is
             * incremented by object size. */
            MVMObject *obj = (MVMObject *)item;
            GCDEBUG_LOG(tc, MVM_GC_DEBUG_COLLECT, "Thread %d run %d : collecting an object %p in the nursery with reprid %d\n", item, REPR(obj)->ID);
            if (dead && REPR(obj)->gc_free)
                REPR(obj)->gc_free(tc, obj);
        }
        else if (item->flags & MVM_CF_TYPE_OBJECT) {
            /* Type object; doesn't have anything extra that needs freeing. */
        }
        else if (item->flags & MVM_CF_STABLE) {
            MVMSTable *st = (MVMSTable *)item;
            if (dead) {
/*            GCDEBUG_LOG(tc, MVM_GC_DEBUG_COLLECT, "Thread %d run %d : enqueuing an STable %d in the nursery to be freed\n", item);*/
                MVM_gc_collect_enqueue_stable_for_deletion(tc, st);
            }
        }
        else {
            printf("item flags: %d\n", item->flags);
            MVM_panic(MVM_exitcode_gcnursery, "Internal error: impossible case encountered in GC free");
        }

        /* Go to the next item. */
        scan = (char *)scan + item->size;
    }
}
Example #2
0
/* Goes through the unmarked objects in the second generation heap and builds
 * free lists out of them. Also does any required finalization. */
void MVM_gc_collect_free_gen2_unmarked(MVMThreadContext *tc, MVMint32 global_destruction) {
    /* Visit each of the size class bins. */
    MVMGen2Allocator *gen2 = tc->gen2;
    MVMuint32 bin, obj_size, page, i;
    char ***freelist_insert_pos;
    for (bin = 0; bin < MVM_GEN2_BINS; bin++) {
        /* If we've nothing allocated in this size class, skip it. */
        if (gen2->size_classes[bin].pages == NULL)
            continue;

        /* Calculate object size for this bin. */
        obj_size = (bin + 1) << MVM_GEN2_BIN_BITS;

        /* freelist_insert_pos is a pointer to a memory location that
         * stores the address of the last traversed free list node (char **). */
        /* Initialize freelist insertion position to free list head. */
        freelist_insert_pos = &gen2->size_classes[bin].free_list;

        /* Visit each page. */
        for (page = 0; page < gen2->size_classes[bin].num_pages; page++) {
            /* Visit all the objects, looking for dead ones and reset the
             * mark for each of them. */
            char *cur_ptr = gen2->size_classes[bin].pages[page];
            char *end_ptr = page + 1 == gen2->size_classes[bin].num_pages
                ? gen2->size_classes[bin].alloc_pos
                : cur_ptr + obj_size * MVM_GEN2_PAGE_ITEMS;
            while (cur_ptr < end_ptr) {
                MVMCollectable *col = (MVMCollectable *)cur_ptr;

                /* Is this already a free list slot? If so, it becomes the
                 * new free list insert position. */
                if (*freelist_insert_pos == (char **)cur_ptr) {
                    freelist_insert_pos = (char ***)cur_ptr;
                }

                /* Otherwise, it must be a collectable of some kind. Is it
                 * live? */
                else if (col->flags & MVM_CF_GEN2_LIVE) {
                    /* Yes; clear the mark. */
                    col->flags &= ~MVM_CF_GEN2_LIVE;
                }
                else {
                    GCDEBUG_LOG(tc, MVM_GC_DEBUG_COLLECT, "Thread %d run %d : collecting an object %p in the gen2\n", col);
                    /* No, it's dead. Do any cleanup. */
                    if (!(col->flags & (MVM_CF_TYPE_OBJECT | MVM_CF_STABLE))) {
                        /* Object instance; call gc_free if needed. */
                        MVMObject *obj = (MVMObject *)col;
                        if (STABLE(obj) && REPR(obj)->gc_free)
                            REPR(obj)->gc_free(tc, obj);
#ifdef MVM_USE_OVERFLOW_SERIALIZATION_INDEX
                        if (col->flags & MVM_CF_SERIALZATION_INDEX_ALLOCATED)
                            MVM_free(col->sc_forward_u.sci);
#endif
                    }
                    else if (col->flags & MVM_CF_TYPE_OBJECT) {
#ifdef MVM_USE_OVERFLOW_SERIALIZATION_INDEX
                        if (col->flags & MVM_CF_SERIALZATION_INDEX_ALLOCATED)
                            MVM_free(col->sc_forward_u.sci);
#endif
                    }
                    else if (col->flags & MVM_CF_STABLE) {
                        if (
#ifdef MVM_USE_OVERFLOW_SERIALIZATION_INDEX
                            !(col->flags & MVM_CF_SERIALZATION_INDEX_ALLOCATED) &&
#endif
                            col->sc_forward_u.sc.sc_idx == 0
                            && col->sc_forward_u.sc.idx == MVM_DIRECT_SC_IDX_SENTINEL) {
                            /* We marked it dead last time, kill it. */
                            MVM_6model_stable_gc_free(tc, (MVMSTable *)col);
                        }
                        else {
#ifdef MVM_USE_OVERFLOW_SERIALIZATION_INDEX
                            if (col->flags & MVM_CF_SERIALZATION_INDEX_ALLOCATED) {
                                /* Whatever happens next, we can free this
                                   memory immediately, because no-one will be
                                   serializing a dead STable. */
                                assert(!(col->sc_forward_u.sci->sc_idx == 0
                                         && col->sc_forward_u.sci->idx
                                         == MVM_DIRECT_SC_IDX_SENTINEL));
                                MVM_free(col->sc_forward_u.sci);
                                col->flags &= ~MVM_CF_SERIALZATION_INDEX_ALLOCATED;
                            }
#endif
                            if (global_destruction) {
                                /* We're in global destruction, so enqueue to the end
                                 * like we do in the nursery */
                                MVM_gc_collect_enqueue_stable_for_deletion(tc, (MVMSTable *)col);
                            } else {
                                /* There will definitely be another gc run, so mark it as "died last time". */
                                col->sc_forward_u.sc.sc_idx = 0;
                                col->sc_forward_u.sc.idx = MVM_DIRECT_SC_IDX_SENTINEL;
                            }
                            /* Skip the freelist updating. */
                            cur_ptr += obj_size;
                            continue;
                        }
                    }
                    else {
                        printf("item flags: %d\n", col->flags);
                        MVM_panic(MVM_exitcode_gcnursery, "Internal error: impossible case encountered in gen2 GC free");
                    }

                    /* Chain in to the free list. */
                    *((char **)cur_ptr) = (char *)*freelist_insert_pos;
                    *freelist_insert_pos = (char **)cur_ptr;

                    /* Update the pointer to the insert position to point to us */
                    freelist_insert_pos = (char ***)cur_ptr;
                }

                /* Move to the next object. */
                cur_ptr += obj_size;
            }
        }
    }
    
    /* Also need to consider overflows. */
    for (i = 0; i < gen2->num_overflows; i++) {
        if (gen2->overflows[i]) {
            MVMCollectable *col = gen2->overflows[i];
            if (col->flags & MVM_CF_GEN2_LIVE) {
                /* A living over-sized object; just clear the mark. */
                col->flags &= ~MVM_CF_GEN2_LIVE;
            }
            else {
                /* Dead over-sized object. We know if it's this big it cannot
                 * be a type object or STable, so only need handle the simple
                 * object case. */
                if (!(col->flags & (MVM_CF_TYPE_OBJECT | MVM_CF_STABLE))) {
                    MVMObject *obj = (MVMObject *)col;
                    if (REPR(obj)->gc_free)
                        REPR(obj)->gc_free(tc, obj);
#ifdef MVM_USE_OVERFLOW_SERIALIZATION_INDEX
                    if (col->flags & MVM_CF_SERIALZATION_INDEX_ALLOCATED)
                        MVM_free(col->sc_forward_u.sci);
#endif
                }
                else {
                    MVM_panic(MVM_exitcode_gcnursery, "Internal error: gen2 overflow contains non-object");
                }
                MVM_free(col);
                gen2->overflows[i] = NULL;
            }
        }
    }
    /* And finally compact the overflow list */
    MVM_gc_gen2_compact_overflows(gen2);
}
Example #3
0
/* Some objects, having been copied, need no further attention. Others
 * need to do some additional freeing, however. This goes through the
 * fromspace and does any needed work to free uncopied things (this may
 * run in parallel with the mutator, which will be operating on tospace). */
void MVM_gc_collect_free_nursery_uncopied(MVMThreadContext *tc, void *limit) {
    /* We start scanning the fromspace, and keep going until we hit
     * the end of the area allocated in it. */
    void *scan = tc->nursery_fromspace;
    while (scan < limit) {
        /* The object here is dead if it never got a forwarding pointer
         * written in to it. */
        MVMCollectable *item = (MVMCollectable *)scan;
        MVMuint8 dead = !(item->flags & MVM_CF_FORWARDER_VALID);

        if (!dead)
            assert(item->sc_forward_u.forwarder != NULL);

        /* Now go by collectable type. */
        if (!(item->flags & (MVM_CF_TYPE_OBJECT | MVM_CF_STABLE))) {
            /* Object instance. If dead, call gc_free if needed. Scan is
             * incremented by object size. */
            MVMObject *obj = (MVMObject *)item;
            GCDEBUG_LOG(tc, MVM_GC_DEBUG_COLLECT, "Thread %d run %d : collecting an object %p in the nursery with reprid %d\n", item, REPR(obj)->ID);
            if (dead && REPR(obj)->gc_free)
                REPR(obj)->gc_free(tc, obj);
#ifdef MVM_USE_OVERFLOW_SERIALIZATION_INDEX
            if (dead && item->flags & MVM_CF_SERIALZATION_INDEX_ALLOCATED)
                MVM_free(item->sc_forward_u.sci);
#endif
            if (dead && item->flags & MVM_CF_HAS_OBJECT_ID)
                MVM_gc_object_id_clear(tc, item);
        }
        else if (item->flags & MVM_CF_TYPE_OBJECT) {
            /* Type object */
#ifdef MVM_USE_OVERFLOW_SERIALIZATION_INDEX
            if (dead && item->flags & MVM_CF_SERIALZATION_INDEX_ALLOCATED)
                MVM_free(item->sc_forward_u.sci);
#endif
            if (dead && item->flags & MVM_CF_HAS_OBJECT_ID)
                MVM_gc_object_id_clear(tc, item);
        }
        else if (item->flags & MVM_CF_STABLE) {
            MVMSTable *st = (MVMSTable *)item;
            if (dead) {
/*            GCDEBUG_LOG(tc, MVM_GC_DEBUG_COLLECT, "Thread %d run %d : enqueuing an STable %d in the nursery to be freed\n", item);*/
#ifdef MVM_USE_OVERFLOW_SERIALIZATION_INDEX
                if (item->flags & MVM_CF_SERIALZATION_INDEX_ALLOCATED) {
                    MVM_free(item->sc_forward_u.sci);
                    /* Arguably we don't need to do this, if we're always
                       consistent about what we put on the stable queue. */
                    item->flags &= ~MVM_CF_SERIALZATION_INDEX_ALLOCATED;
                }
#endif
                MVM_gc_collect_enqueue_stable_for_deletion(tc, st);
            }
        }
        else {
            printf("item flags: %d\n", item->flags);
            MVM_panic(MVM_exitcode_gcnursery, "Internal error: impossible case encountered in GC free");
        }

        /* Go to the next item. */
        scan = (char *)scan + item->size;
    }
}
Example #4
0
/* Goes through the unmarked objects in the second generation heap and builds
 * free lists out of them. Also does any required finalization. */
void MVM_gc_collect_free_gen2_unmarked(MVMThreadContext *tc) {
    /* Visit each of the size class bins. */
    MVMGen2Allocator *gen2 = tc->gen2;
    MVMuint32 bin, obj_size, page, i;
    char ***freelist_insert_pos;
    for (bin = 0; bin < MVM_GEN2_BINS; bin++) {
        /* If we've nothing allocated in this size class, skip it. */
        if (gen2->size_classes[bin].pages == NULL)
            continue;

        /* Calculate object size for this bin. */
        obj_size = (bin + 1) << MVM_GEN2_BIN_BITS;

        /* freelist_insert_pos is a pointer to a memory location that
         * stores the address of the last traversed free list node (char **). */
        /* Initialize freelist insertion position to free list head. */
        freelist_insert_pos = &gen2->size_classes[bin].free_list;

        /* Visit each page. */
        for (page = 0; page < gen2->size_classes[bin].num_pages; page++) {
            /* Visit all the objects, looking for dead ones and reset the
             * mark for each of them. */
            char *cur_ptr = gen2->size_classes[bin].pages[page];
            char *end_ptr = page + 1 == gen2->size_classes[bin].num_pages
                ? gen2->size_classes[bin].alloc_pos
                : cur_ptr + obj_size * MVM_GEN2_PAGE_ITEMS;
            char **last_insert_pos = NULL;
            while (cur_ptr < end_ptr) {
                MVMCollectable *col = (MVMCollectable *)cur_ptr;

                /* Is this already a free list slot? If so, it becomes the
                 * new free list insert position. */
                if (*freelist_insert_pos == (char **)cur_ptr) {
                    freelist_insert_pos = (char ***)cur_ptr;
                }

                /* Otherwise, it must be a collectable of some kind. Is it
                 * live? */
                else if (col->forwarder) {
                    /* Yes; clear the mark. */
                    col->forwarder = NULL;
                }
                else {
                    GCDEBUG_LOG(tc, MVM_GC_DEBUG_COLLECT, "Thread %d run %d : collecting an object %p in the gen2\n", col);
                    /* No, it's dead. Do any cleanup. */
                    if (!(col->flags & (MVM_CF_TYPE_OBJECT | MVM_CF_STABLE))) {
                        /* Object instance; call gc_free if needed. */
                        MVMObject *obj = (MVMObject *)col;
                        if (REPR(obj)->gc_free)
                            REPR(obj)->gc_free(tc, obj);
                    }
                    else if (col->flags & MVM_CF_TYPE_OBJECT) {
                        /* Type object; doesn't have anything extra that needs freeing. */
                    }
                    else if (col->flags & MVM_CF_STABLE) {
                        if (col->sc == (MVMSerializationContext *)1) {
                            /* We marked it dead last time, kill it. */
                            MVM_6model_stable_gc_free(tc, (MVMSTable *)col);
                        }
                        else {
                            if (MVM_load(&tc->gc_status) == MVMGCStatus_NONE) {
                                /* We're in global destruction, so enqueue to the end
                                 * like we do in the nursery */
                                MVM_gc_collect_enqueue_stable_for_deletion(tc, (MVMSTable *)col);
                            } else {
                                /* There will definitely be another gc run, so mark it as "died last time". */
                                col->sc = (MVMSerializationContext *)1;
                            }
                            /* Skip the freelist updating. */
                            cur_ptr += obj_size;
                            continue;
                        }
                    }
                    else {
                        printf("item flags: %d\n", col->flags);
                        MVM_panic(MVM_exitcode_gcnursery, "Internal error: impossible case encountered in gen2 GC free");
                    }

                    /* Chain in to the free list. */
                    *((char **)cur_ptr) = (char *)*freelist_insert_pos;
                    *freelist_insert_pos = (char **)cur_ptr;

                    /* Update the pointer to the insert position to point to us */
                    freelist_insert_pos = (char ***)cur_ptr;
                }

                /* Move to the next object. */
                cur_ptr += obj_size;
            }
        }
    }
    
    /* Also need to consider overflows. */
    for (i = 0; i < gen2->num_overflows; i++) {
        if (gen2->overflows[i]) {
            MVMCollectable *col = gen2->overflows[i];
            if (col->forwarder) {
                /* A living over-sized object; just clear the mark. */
                col->forwarder = NULL;
            }
            else {
                /* Dead over-sized object. We know if it's this big it cannot
                 * be a type object or STable, so only need handle the simple
                 * object case. */
                if (!(col->flags & (MVM_CF_TYPE_OBJECT | MVM_CF_STABLE))) {
                    MVMObject *obj = (MVMObject *)col;
                    if (REPR(obj)->gc_free)
                        REPR(obj)->gc_free(tc, obj);
                }
                else {
                    MVM_panic(MVM_exitcode_gcnursery, "Internal error: gen2 overflow contains non-object");
                }
                free(col);
                gen2->overflows[i] = NULL;
            }
        }
    }
}