This is GarbageCollector.m in view mode; [Download] [Up]
/* GarbageCollector.m Copyright (C) 1995, 1996 Ovidiu Predescu and Mircea Oancea. All rights reserved. Author: Ovidiu Predescu <ovidiu@bx.logicnet.ro> This file is part of libFoundation. Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. We disclaim all warranties with regard to this software, including all implied warranties of merchantability and fitness, in no event shall we be liable for any special, indirect or consequential damages or any damages whatsoever resulting from loss of use, data or profits, whether in an action of contract, negligence or other tortious action, arising out of or in connection with the use or performance of this software. */ #include <Foundation/NSArray.h> #include <extensions/objc-runtime.h> #include <extensions/GCObject.h> #include <extensions/GarbageCollector.h> @interface __DummyGCObject : GCObject @end @implementation __DummyGCObject + allocWithZone:(NSZone*)zone { return NSAllocateObject(self, 0, zone); } - (void)dealloc { } @end /* The GCDoubleLinkedList is a double linked list which contains as the first element a dummy GCObject. This object is always the head of the list. A new element is introduced immediately after the head. This way we don't need to keep track of the head of the list when we remove an element. */ @interface GCDoubleLinkedList : NSObject { id list; } - (void)addObject:(id)anObject; - (void)removeObject:(id)anObject; - (id)firstObject; - (void)removeAllObjects; @end @implementation GCDoubleLinkedList - init { list = [__DummyGCObject new]; return self; } - (void)addObject:(id)anObject { id next = [list gcNextObject]; [list gcSetNextObject:anObject]; [anObject gcSetNextObject:next]; [next gcSetPreviousObject:anObject]; [anObject gcSetPreviousObject:list]; } - (void)removeObject:(id)anObject { id prev = [anObject gcPreviousObject]; id next = [anObject gcNextObject]; [prev gcSetNextObject:next]; [next gcSetPreviousObject:prev]; } - (id)firstObject { return [list gcNextObject]; } - (void)removeAllObjects { [list gcSetNextObject:nil]; } @end @implementation GarbageCollector static id gcObjectsToBeVisited; static BOOL isGarbageCollecting = NO; + (void)initialize { gcObjectsToBeVisited = [GCDoubleLinkedList new]; } + (void)collectGarbages { id object; isGarbageCollecting = YES; /* First pass. All the objects in the gcObjectsToBeVisited list receive the -decrementRefCount message. Each object should decrement the ref count of all objects contained. */ object = [gcObjectsToBeVisited firstObject]; while(object) { [object gcDecrementRefCountOfContainedObjects]; [object gcSetVisited:NO]; object = [object gcNextObject]; }; /* Second pass. All the objects in the gcObjectsToBeVisited list that have the refCount greater than 0 receive the -incrementRefCount message. Each object should increment the ref count of all objects contained. Then it should send the -incrementRefCount message to all objects contained. */ object = [gcObjectsToBeVisited firstObject]; while(object) { if([object retainCount]) [object gcIncrementRefCountOfContainedObjects]; object = [object gcNextObject]; } /* Third pass. All the objects that still have the refCount equal with 0 are part of cyclic graphs and none of the objects from this graph are held by some object outside graph. These objects receive the -dealloc message. In this method they should send the -dealloc message to objects that are garbage collectable. An object could be asked if it is garbage collectable by sending it the -isGarbageCollectable message. */ object = [gcObjectsToBeVisited firstObject]; while(object) { if([object retainCount] == 0) { id nextObject = [object gcNextObject]; /* Remove object from gcObjectsToBeVisited list. We have to keep the old nextObject because after removing the object from list its nextObject is altered. */ [gcObjectsToBeVisited removeObject:object]; [object dealloc]; object = nextObject; } else object = [object gcNextObject]; } isGarbageCollecting = NO; } + (void)addObject:(id)anObject { [gcObjectsToBeVisited addObject:anObject]; } + (void)objectWillBeDeallocated:(id)anObject { /* We can remove without fear the object from its list because the head of the list is always the same. */ id prev = [anObject gcPreviousObject]; id next = [anObject gcNextObject]; [prev gcSetNextObject:next]; [next gcSetPreviousObject:prev]; } + (BOOL)isGarbageCollecting { return isGarbageCollecting; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.