1 // Copyright (c) 1996 James Clark
2 // See the file copying.txt for copying permission.
13 Collector::Collector(size_t maxSize)
14 : freePtr_(&allObjectsList_), currentColor_(Object::someColor),
15 blocks_(0), lastTraced_(0), totalObjects_(0), maxSize_(maxSize)
17 allObjectsList_.makeHead();
18 permanentFinalizersList_.makeHead();
21 Collector::~Collector()
23 if (freePtr_ != &allObjectsList_) {
24 for (Object *p = allObjectsList_.next(); p != freePtr_; p = p->next()) {
25 if (!p->hasFinalizer_)
31 for (Object *p = permanentFinalizersList_.next();
32 p != &permanentFinalizersList_;
34 ASSERT(p->hasFinalizer_);
40 blocks_ = blocks_->next;
45 void Collector::makeSpace()
47 unsigned long nLive = collect();
48 // Ensure that at least one-quarter of the heap is free, but don't allocate fewer
50 if (freePtr_ == &allObjectsList_ || totalObjects_ - nLive < (totalObjects_ >> 2)
51 || totalObjects_ < 128) {
53 if (totalObjects_ < 128)
56 allocObjs = (totalObjects_ >> 2) - (totalObjects_ - nLive);
60 if (freePtr_ == &allObjectsList_) {
61 blocks_ = new Block(blocks_, allocObjs, maxSize_, freePtr_->prev());
62 freePtr_ = blocks_->firstObj;
65 blocks_ = new Block(blocks_, allocObjs, maxSize_, freePtr_);
66 totalObjects_ += allocObjs;
73 void Collector::check()
78 bool allowFinalizer = 1;
79 for (Object *p = allObjectsList_.next();
80 p != &allObjectsList_;
85 if (p->color() != currentColor_)
88 if (!p->hasFinalizer_)
91 else if (p->hasFinalizer_)
94 if (p->next()->prev() != p)
96 if (p->prev()->next() != p)
100 if (n != totalObjects_)
105 // Link block in after follow.
107 Collector::Block::Block(Block *p, size_t n, size_t sz, Object *follow)
110 Object *next = follow->next_;
111 Object *prev = follow;
112 Object *cur = (Object *)::operator new(n * sz);
113 firstObj = follow->next_ = cur;
114 for (size_t i = 0; i < n; i++) {
115 Object *tem = (i == n - 1 ? next : (Object *)((char *)cur + sz));
124 unsigned long Collector::collect()
126 Object *oldFreePtr = freePtr_;
127 unsigned long nLive = 0;
128 currentColor_ = (currentColor_ == Object::someColor
129 ? Object::anotherColor
130 : Object::someColor);
131 lastTraced_ = &allObjectsList_;
134 if (lastTraced_ != &allObjectsList_) {
135 Object *scanPtr = allObjectsList_.next();
137 if (scanPtr->hasSubObjects())
138 scanPtr->traceSubObjects(*this);
140 Object *next = scanPtr->next();
141 if (scanPtr->hasFinalizer_)
142 scanPtr->moveAfter(&allObjectsList_);
143 if (scanPtr == lastTraced_) {
151 freePtr_ = allObjectsList_.next();
153 for (Object *p = freePtr_; p != oldFreePtr; p = p->next()) {
154 if (!p->hasFinalizer_)
164 void Collector::makePermanent(Object *obj)
166 if (!obj->hasSubObjects()) {
167 // Handle the simple case quickly.
168 if (obj->color() != Object::permanentColor) {
170 obj->setColor(Object::permanentColor);
172 if (obj->hasFinalizer_)
173 obj->moveAfter(&permanentFinalizersList_);
175 obj->next_->prev_ = obj->prev_;
176 obj->prev_->next_ = obj->next_;
181 Object::Color saveColor = currentColor_;
182 currentColor_ = Object::permanentColor;
183 lastTraced_ = &allObjectsList_;
185 if (lastTraced_ != &allObjectsList_) {
186 Object *scanPtr = allObjectsList_.next();
188 scanPtr->readOnly_ = 1;
189 if (scanPtr->hasSubObjects())
190 scanPtr->traceSubObjects(*this);
192 Object *next = scanPtr->next();
193 if (scanPtr->hasFinalizer_)
194 scanPtr->moveAfter(&permanentFinalizersList_);
196 // unlink from allObjectsList_
197 scanPtr->next_->prev_ = scanPtr->prev_;
198 scanPtr->prev_->next_ = scanPtr->next_;
200 if (scanPtr == lastTraced_)
206 currentColor_ = saveColor;
210 void Collector::makeReadOnly1(Object *obj)
212 Object::Color saveColor = currentColor_;
213 currentColor_ = (currentColor_ == Object::someColor
214 ? Object::anotherColor
215 : Object::someColor);
216 lastTraced_ = &allObjectsList_;
218 if (lastTraced_ != &allObjectsList_) {
219 Object *scanPtr = allObjectsList_.next();
220 Object *firstNonFinal = 0;
223 if (scanPtr->hasSubObjects())
224 scanPtr->traceSubObjects(*this);
225 Object *next = scanPtr->next();
226 if (scanPtr->hasFinalizer_)
227 scanPtr->moveAfter(&allObjectsList_);
228 else if (!firstNonFinal)
229 firstNonFinal = scanPtr;
230 if (scanPtr == lastTraced_) {
236 // We have 1 or more objects to be made read-only in currentColor
237 // Followed by 0 or more objects with finalizers in saveColor
238 // Followed by 0 or more objects without finalizers in saveColor
239 for (scanPtr = allObjectsList_.next(); scanPtr != lim; scanPtr = scanPtr->next()) {
240 scanPtr->readOnly_ = 1;
241 scanPtr->setColor(saveColor);
245 scanPtr != freePtr_ && scanPtr->hasFinalizer_;
246 scanPtr = scanPtr->next())
248 if (scanPtr != lim) {
249 Object *last = lim->prev();
250 // Move section of list from firstNonFinal up to lastTraced but not including
251 // lim to before scanPtr
252 firstNonFinal->prev()->next_ = last->next();
253 last->next()->prev_ = firstNonFinal->prev();
254 firstNonFinal->prev_ = scanPtr->prev();
255 last->next_ = scanPtr->prev()->next();
256 firstNonFinal->prev()->next_ = firstNonFinal;
257 last->next()->prev_ = last;
262 currentColor_ = saveColor;
268 void Collector::traceDynamicRoots()
270 for (DynamicRoot *p = dynRootList_.next_; p != &dynRootList_; p = p->next_)
274 Collector::DynamicRoot::~DynamicRoot()
279 void Collector::unallocateObject(void *obj)
281 ((Object *)obj)->moveAfter(freePtr_);