Example #1
0
// Tests if this needs to be scanned.  It marks it if it has not been marked
// unless it has to be scanned.
bool MTGCProcessMarkPointers::TestForScan(PolyWord *pt)
{
    if ((*pt).IsTagged())
        return false;

    // This could contain a forwarding pointer if it points into an
    // allocation area and has been moved by the minor GC.
    // We have to be a little careful.  Another thread could also
    // be following any forwarding pointers here.  However it's safe
    // because they will update it with the same value.
    PolyObject *obj = (*pt).AsObjPtr();
    if (obj->ContainsForwardingPtr())
    {
        obj = FollowForwarding(obj);
        *pt = obj;
    }

    if (gMem.LocalSpaceForAddress(obj) == 0)
        return false; // Ignore it if it points to a permanent area

    POLYUNSIGNED L = obj->LengthWord();
    if (L & _OBJ_GC_MARK)
        return false; // Already marked

    if (debugOptions & DEBUG_GC_DETAIL)
        Log("GC: Mark: %p %" POLYUFMT " %u\n", obj, OBJ_OBJECT_LENGTH(L), GetTypeBits(L));

    if (OBJ_IS_BYTE_OBJECT(L))
    {
        obj->SetLengthWord(L | _OBJ_GC_MARK); // Mark it
        return false; // We've done as much as we need
    }
    return true;
}
Example #2
0
// The initial entry to process the roots.  These may be RTS addresses or addresses in
// a thread stack.  Also called recursively to process the addresses of constants in
// code segments.  This is used in situations where a scanner may return the
// updated address of an object.
PolyObject *MTGCProcessMarkPointers::ScanObjectAddress(PolyObject *obj)
{
    PolyWord val = obj;
    LocalMemSpace *space = gMem.LocalSpaceForAddress(val.AsAddress());
    if (space == 0)
        return obj; // Ignore it if it points to a permanent area

    // We may have a forwarding pointer if this has been moved by the
    // minor GC.
    if (obj->ContainsForwardingPtr())
    {
        obj = FollowForwarding(obj);
        val = obj;
        space = gMem.LocalSpaceForAddress(val.AsAddress());
    }

    ASSERT(obj->ContainsNormalLengthWord());

    POLYUNSIGNED L = obj->LengthWord();
    if (L & _OBJ_GC_MARK)
        return obj; // Already marked
    obj->SetLengthWord(L | _OBJ_GC_MARK); // Mark it

    if (profileMode == kProfileLiveData || (profileMode == kProfileLiveMutables && obj->IsMutable()))
        AddObjectProfile(obj);

    POLYUNSIGNED n = OBJ_OBJECT_LENGTH(L);
    if (debugOptions & DEBUG_GC_DETAIL)
        Log("GC: Mark: %p %" POLYUFMT " %u\n", obj, n, GetTypeBits(L));

    if (OBJ_IS_BYTE_OBJECT(L))
        return obj;

    // If we already have something on the stack we must being called
    // recursively to process a constant in a code segment.  Just push
    // it on the stack and let the caller deal with it.
    if (msp != 0)
        PushToStack(obj); // Can't check this because it may have forwarding ptrs.
    else
    {
        MTGCProcessMarkPointers::ScanAddressesInObject(obj, L);

        // We can only check after we've processed it because if we
        // have addresses left over from an incomplete partial GC they
        // may need to forwarded.
        CheckObject (obj);
    }

    return obj;
}
Example #3
0
void DoCheckObject (const PolyObject *base, POLYUNSIGNED L)
{

    PolyWord *pt  = (PolyWord*)base;
    CheckAddress(pt);
    MemSpace *space = gMem.SpaceForAddress(pt-1);
    if (space == 0)
        Crash ("Bad pointer 0x%08" PRIxPTR " found", (uintptr_t)pt);

    ASSERT (OBJ_IS_LENGTH(L));

    POLYUNSIGNED n   = OBJ_OBJECT_LENGTH(L);
    if (n == 0) return;

    ASSERT (n > 0);
    ASSERT(pt-1 >= space->bottom && pt+n <= space->top);

    byte flags = GetTypeBits(L);  /* discards GC flag and mutable bit */

    if (flags == F_BYTE_OBJ) /* possibly signed byte object */
        return; /* Nothing more to do */

    if (flags == F_CODE_OBJ) /* code object */
    {
        ScanCheckAddress checkAddr;
        /* We flush the instruction cache here in case we change any of the
          instructions when we update addresses. */
        machineDependent->FlushInstructionCache(pt, (n + 1) * sizeof(PolyWord));
        machineDependent->ScanConstantsWithinCode((PolyObject *)base, (PolyObject *)base, n, &checkAddr);
        /* Skip to the constants. */
        base->GetConstSegmentForCode(n, pt, n);
    }
    else if (flags == F_CLOSURE_OBJ)
    {
        n -= sizeof(PolyObject*) / sizeof(PolyWord);
        pt += sizeof(PolyObject*) / sizeof(PolyWord);
    }
    else ASSERT (flags == 0); /* ordinary word object */

    while (n--) DoCheck (*pt++);
}
Example #4
0
// Copy objects from the source space into an earlier space or up within the
// current space.
static void copyAllData(GCTaskId *id, void * /*arg1*/, void * /*arg2*/)
{
    LocalMemSpace *mutableDest = 0, *immutableDest = 0;

    for (std::vector<LocalMemSpace*>::reverse_iterator i = gMem.lSpaces.rbegin(); i != gMem.lSpaces.rend(); i++)
    {
        LocalMemSpace *src = *i;

        if (src->spaceOwner == 0)
        {
            PLocker lock(&copyLock);
            if (src->spaceOwner == 0)
                src->spaceOwner = id;
            else continue;
        }
        else if (src->spaceOwner != id)
            continue;

        if (debugOptions & DEBUG_GC_ENHANCED)
            Log("GC: Copy: copying area %p (thread %p) %s \n", src, id, src->spaceTypeString());

        // We start at fullGCLowerLimit which is the lowest marked object in the heap
        // N.B.  It's essential that the first set bit at or above this corresponds
        // to the length word of a real object.
        uintptr_t  bitno   = src->wordNo(src->fullGCLowerLimit);
        // Set the limit to the top so we won't rescan this.  That can
        // only happen if copying takes a very short time and the same
        // thread runs multiple tasks.
        src->fullGCLowerLimit = src->top;

        // src->highest is the bit position that corresponds to the top of
        // generation we're copying.
        uintptr_t  highest = src->wordNo(src->top);

        for (;;)
        {
            if (bitno >= highest) break;

            /* SPF version; Invariant: 0 < highest - bitno */
            bitno += src->bitmap.CountZeroBits(bitno, highest - bitno);

            if (bitno >= highest) break;

            /* first set bit corresponds to the length word */
            PolyWord *old = src->wordAddr(bitno); /* Old object address */

            PolyObject *obj = (PolyObject*)(old+1);

            POLYUNSIGNED L = obj->LengthWord();
            ASSERT (OBJ_IS_LENGTH(L));

            POLYUNSIGNED n = OBJ_OBJECT_LENGTH(L) + 1 ;/* Length of allocation (including length word) */
            bitno += n;

            // Find a mutable space for the mutable objects and an immutable space for
            // the immutables.  We copy objects into earlier spaces or within its own
            // space but we don't copy an object to a later space.  This avoids the
            // risk of copying an object multiple times.  Previously this copied objects
            // into later spaces but that doesn't work well if we have converted old
            // saved state segments into local areas.  It's much better to delete them
            // if possible.
            bool isMutable = OBJ_IS_MUTABLE_OBJECT(L);
            LocalMemSpace *destSpace = isMutable || immutableDest == 0 ? mutableDest : immutableDest;
            PolyWord *newp = FindFreeAndAllocate(destSpace, (src == destSpace) ? bitno : 0, n);
            if (newp == 0 && src != destSpace)
            {
                // See if we can find a different space.
                // N.B.  FindNextSpace side-effects mutableDest/immutableDest to give the next space.
                if (FindNextSpace(src, isMutable ? &mutableDest : &immutableDest, isMutable, id))
                {
                    bitno -= n; // Redo this object
                    continue;
                }
                // else just leave it
            }

            if (newp == 0) /* no room */
            {
                // We're not going to move this object
                // Update src->upperAllocPtr, so the old object doesn't get trampled.
                if (old < src->upperAllocPtr)
                    src->upperAllocPtr = old;

                // Previously this continued compressing to try to make space available
                // on the next GC.  Normally full GCs are infrequent so the chances are
                // that at the next GC other data will have been freed.  Just stop at
                // this point.
                // However if we're compressing a mutable area and there is immutable
                // data in it we should move those out because the mutable area is scanned
                // on every partial GC.
                if (! src->isMutable || src->i_marked == 0)
                    break;
            }
            else
            {
                PolyObject *destAddress = (PolyObject*)(newp+1);
                obj->SetForwardingPtr(destAddress);
                CopyObjectToNewAddress(obj, destAddress, L);

                if (debugOptions & DEBUG_GC_DETAIL)
                    Log("GC: Copy: %p %lu %u -> %p\n", obj, OBJ_OBJECT_LENGTH(L),
                                GetTypeBits(L), destAddress);
            }
        }

        if (mutableDest == src)
            mutableDest = 0;
        if (immutableDest == src)
            immutableDest = 0;
    }
}