1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
|
/*
Title: Multi-Threaded Garbage Collector - Check for weak references
Copyright (c) 2010, 2012, 2015 David C. J. Matthews
Based on the original garbage collector code
Copyright 2000-2008
Cambridge University Technical Services Limited
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License version 2.1 as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
This is an intermediate phase in the GC that checks for weak references
that are no longer reachable. It is performed after the first, mark, phase.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#elif defined(_WIN32)
#include "winconfig.h"
#else
#error "No configuration file"
#endif
#ifdef HAVE_ASSERT_H
#include <assert.h>
#define ASSERT(x) assert(x)
#else
#define ASSERT(x)
#endif
#include "globals.h"
#include "gc.h"
#include "scanaddrs.h"
#include "rts_module.h"
#include "memmgr.h"
class MTGCCheckWeakRef: public ScanAddress {
public:
void ScanAreas(void);
private:
virtual void ScanRuntimeAddress(PolyObject **pt, RtsStrength weak);
// This has to be defined since it's virtual.
virtual PolyObject *ScanObjectAddress(PolyObject *base) { return base; }
virtual void ScanAddressesInObject(PolyObject *obj, POLYUNSIGNED lengthWord);
};
// This deals with weak references within the run-time system.
void MTGCCheckWeakRef::ScanRuntimeAddress(PolyObject **pt, RtsStrength weak)
{
/* If the object has not been marked and this is only a weak reference */
/* then the pointer is set to zero. This allows streams or windows */
/* to be closed if there is no other reference to them. */
PolyObject *val = *pt;
PolyWord w = val;
if (weak == STRENGTH_STRONG)
return;
LocalMemSpace *space = gMem.LocalSpaceForAddress(w.AsStackAddr()-1);
if (space == 0)
return; // Not in local area
// If it hasn't been marked set it to zero.
if (! space->bitmap.TestBit(space->wordNo(w.AsStackAddr())))
*pt = 0;
}
// Deal with weak objects
void MTGCCheckWeakRef::ScanAddressesInObject(PolyObject *obj, POLYUNSIGNED L)
{
if (! OBJ_IS_WEAKREF_OBJECT(L) || OBJ_IS_BYTE_OBJECT(L)) return; // Ignore Weak-Byte cells.
ASSERT(OBJ_IS_MUTABLE_OBJECT(L)); // Should be a mutable.
// See if any of the SOME objects contain unreferenced refs.
POLYUNSIGNED length = OBJ_OBJECT_LENGTH(L);
PolyWord *baseAddr = (PolyWord*)obj;
for (POLYUNSIGNED i = 0; i < length; i++)
{
PolyWord someAddr = baseAddr[i];
if (someAddr.IsDataPtr())
{
LocalMemSpace *someSpace = gMem.LocalSpaceForAddress(someAddr.AsStackAddr()-1);
if (someSpace != 0)
{
PolyObject *someObj = someAddr.AsObjPtr();
// If this is a weak object the SOME value may refer to an unreferenced
// ref. If so we have to set this entry to NONE. For safety we also
// set the contents of the SOME to TAGGED(0).
ASSERT(someObj->Length() == 1 && someObj->IsWordObject()); // Should be a SOME node.
PolyWord refAddress = someObj->Get(0);
bool deleteRef = false;
if (refAddress.IsTagged())
// If we have the same SOME cell referenced in two different places
// we will have overwritten the address with TAGGED(0) "For safety".
// We still need to overwrite the new reference to the SOME cell.
deleteRef = true; // We've overwritten it.
else
{
// Usual case: the contents of the SOME cell is the address of a ref.
LocalMemSpace *space = gMem.LocalSpaceForAddress(refAddress.AsStackAddr());
if (space != 0) // If the ref is permanent it's always there.
{
POLYUNSIGNED new_bitno = space->wordNo(refAddress.AsStackAddr());
// It wasn't marked so it's otherwise unreferenced.
if (! space->bitmap.TestBit(new_bitno)) deleteRef = true;
}
}
if (deleteRef)
{
baseAddr[i] = TAGGED(0); // Set it to NONE.
someObj->Set(0, TAGGED(0)); // For safety.
convertedWeak = true;
}
}
}
}
}
// We need to check any weak references both in the areas we are
// currently collecting and any other areas. This actually checks
// weak refs in the area we're collecting even if they are not
// actually reachable any more. N.B. This differs from OpMutables
// because it also scans the area we're collecting.
void MTGCCheckWeakRef::ScanAreas(void)
{
for (std::vector<LocalMemSpace*>::iterator i = gMem.lSpaces.begin(); i < gMem.lSpaces.end(); i++)
{
LocalMemSpace *space = *i;
if (space->isMutable)
ScanAddressesInRegion(space->lowestWeak, space->highestWeak);
}
// Scan the permanent mutable areas.
for (std::vector<PermanentMemSpace*>::iterator i = gMem.pSpaces.begin(); i < gMem.pSpaces.end(); i++)
{
MemSpace *space = *i;
if (space->isMutable)
ScanAddressesInRegion(space->lowestWeak, space->highestWeak);
}
}
void GCheckWeakRefs()
{
MTGCCheckWeakRef checkRef;
GCModules(&checkRef);
checkRef.ScanAreas();
}
|