     START-INFO-DIR-ENTRY
     * libFoundation::                      An OpenStep Foundation library.
     END-INFO-DIR-ENTRY

This file documents the features of the libFoundation library.

Copyright (C) 1995, 1996, 1997, 1998 Ovidiu Predescu and Mircea Oancea. All rights reserved.

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. This softare may be included in any commercial product provided that its distribution contain the libFoundation copyright notice and this permission notice.

The libFoundation Library Manual may be reproduced and distributed in whole or in part, in any medium, physical or electronic, so long as this copyright notice remains intact and unchanged on all copies.

Top
***

Introduction
************

This document describes some of the features and particularities implemented in libFoundation; they are also available in the FoundationExtensions library so that users of libFoundation can use their code with other OpenStep Foundation implementations.

This documentation does not provide yet a full description of all the classes throughout the library. However any documentation that describes the OpenStep's Foundation library should be good enough for the classes implemented by libFoundation.

Below are some resources that provide additional information about the OpenStep Foundation classes:

  * The original OpenStep specification can be found at:

     http://www.gnustep.org/GNUOpenStep/OpenStepSpec/OpenStepSpec.html.

  * OPENSTEP/Rhapsody related documentation, you can find here a very good documentation for Foundation:

     http://developer.apple.com/techpubs/rhapsody/rhapsody.html.

  * The GNUstep site, http://www.gnustep.org or the European mirror-site,

     http://www.nmr.embl-heidelberg.de/GNUstep.

Coding with libFoundation
*************************

There are some things one has to know when porting an OpenStep program to work with libFoundation. These things do not change the general behavior of the program, they only make the program work properly with the library.

Preprocessor defines
====================

libFoundation defines some preprocessor values so you can check for them if you want to conditionally pass some code to the compiler. The following macros are defined in Foundation/NSObject.h:

     #define LIB_FOUNDATION_LIBRARY 1

     #define LIB_FOUNDATION_MAJOR_VERSION 0
     #define LIB_FOUNDATION_MINOR_VERSION 9
     #define LIB_FOUNDATION_SUBMINOR_VERSION 0

If you want to include a portion of code that is specific to libFoundation you should put it inside an #ifdef preprocessor command:

     #ifdef LIB_FOUNDATION_LIBRARY
     ...
     #endif

This way you the code inside #ifdef is compiled only in the presence of libFoundation and will not affect other libraries.

Another macro which is defined only when the Boehm's garbage collector is used (see Boehm garbage collector) is LIB_FOUNDATION_BOEHM_GC. You can use it to check in your code whether the code is compiled with support for Boehm's garbage collector or not.

Initializing your program
=========================

It is very important to properly initialize some libFoundation internal data structures when the program starts. These information are mainly related to the NSProcessInfo class. Because not on all platforms is possible to find out the arguments and the environment variables passed to the program, we have chosen to explicitly delegate this task to user. The first lines in a libFoundation program, before creating any other objects, should be the following:

     int main (int argc, char** argv, char** env)
     {
         /* Declarations here */
     ...

     #ifdef LIB_FOUNDATION_LIBRARY
         [NSProcessInfo initializeWithArguments:argv
                        count:argc
                        environment:env];
     #endif

         /* Objects initialization and other instructions here */
         ...
     }

Specifying the resources directory
==================================

It is common to want to try the tests before you have installed the library in its default place. libFoundation however requires to have access to the resource files to function correctly. You can install only the resources in the installation directory, but there is a more convenient way to let the library where are its resources. You can specify an environment variable that indicates where is the resource directory; the name of this variable is LIB_FOUNDATION_RESOURCES_PATH and it should indicate the Resources directory. In a sh-like shell for example, you can do:

     LIB_FOUNDATION_RESOURCES_PATH=/home/ovidiu\
             /libFoundation-0.9.0/libFoundation/Resources
     export LIB_FOUNDATION_RESOURCES_PATH

This environment variable is similar with the PATH variable: you can specify more directories by separating them using : character. Specifying resource directories this way takes precedence over the default installation directory. You can use this to change the resources if you want.

Objective-C runtime support
===========================

Currently there are two different Objective-C runtimes supported by libFoundation: the original NeXT runtime and the GNU runtime which is modelled after it.

The differences between the two runtimes resides mainly in the naming of functions. However there are differences that make the two runtimes incompatible. The most important one is how the selectors are kept.

On NeXT runtime a selector is simply a unique string that represents its name. On GNU runtime, a selector is a structure consisting from a selector id (that is not its name) and a string describing its types. The both approaches have advantages and disadvantages. In the NeXT approach no matter how many times you request a selector (either using the @selector directive or by sel_getUid(), you get the same selector. This is possible because the selector is simply represented as a unique string. On the GNU runtime each time you request a selector using the @selector directive you get a different selector. Moreover the obtained selector has the types member set to NULL.

In the NeXT approach the encoding of the selector's types are bound to each class that has a corresponding method. In the GNU approach the selector's types are bound to the selector.

This differences have deep implication on how the NSProxy class handle a method call in the forwardInvocation: method. On the NeXT runtime, the proxy should make a request to the remote side to obtain the types of the method. The types are used locally by a NSMethodSignature object to determine an encoding. This encoding is used to access correctly the arguments on the stack. However you have the possibility to set a protocol to the NSProxy object at which the remote object answer. This should be done to avoid asking the true object about its selector types and so to increase performance.

On the GNU runtime this is not necessarily because in the forwardInvocation: method the selector usually comes with types in it. However there are cases when this is not true and the same mechanism like in the NeXT case should be applied.

Because the remote machine could be different than the local one, the NSMethodSignature class should be able to create the correct encoding from the types received from remote. Thus the NSMethodSignature class is dependent on the target machine.

This implementation of Foundation works with both runtimes. The extensions/objc-runtime.h file defines the runtime functions to be those from the GNU runtime. All the NeXT runtime functions are defined in terms of GNU runtime functions.

In order to write portable programs for both runtimes you should never use functions in the GNU runtime that work with the types associated with the selector. So the sel_get_type, sel_get_any_uid and sel_get_typed_uid cannot be used in programs. Also you should never use functions like objc_msgSend or objc_msgSendv. Use the objc_msg_sendv function or the NSInvocation class instead.

Never use types like Method in the NeXT runtime or Method_t in the GNU runtime. Use instead the type struct objc_method*. This exists in both runtimes.

Exception handling
******************

The exception handling mechanism provides several powerful features found in languages like C++ or Java. It extends the normal OpenStep exception handling, while still maintaining the backward compatibility with this. A program using the extended exception handling mechanism is still able to work with the normal OpenStep exception handling and viceversa.

The first powerful feature is that you have exceptions grouped by classes. This means you can group exceptions in a hierarchy; not only a tree like but even as a general graph. This feature is present in C++ and with some restrictions in Java.

Another feature is that the exception handler is called as a function. So if you are in debugger you can see the whole stack frame from the point that generated the exception up to the exception handler. So you are able to see what were the conditions that made the exception to be raised.

The actual mechanism is based on nested functions, an extension to the C language. This extension is currently supported by the GNU C Compiler. The actual mechanism is written using macros, so there is no need for special support from the compiler.

A code written using these macros looks like this:

     TRY {
         some code that can generate an exception
     } END_TRY
     CATCH(ExceptionClass1) {
         code to handle an exception of class ExceptionClass1
     }
     CATCH(ExceptionClass2) {
         code to handle an exception of class ExceptionClass2
     }
     ...
     OTHERWISE {
         catch all exceptions not handled above
     }
     END_CATCH

In the TRY block the code that is supposed to generate an exception is executed. You can nest TRY blocks by entering other blocks of code in TRY blocks. All TRY blocks form a stack with the most recent TRY block which is executing on the top of the stack.

If nothing happens during the execution of code inside a TRY block, the program continues with the first statement after the END_CATCH label. When this thing happens the topmost TRY block is popped off the exception handlers stack.

To generate an exception you should allocate an exception object and pass it to the THROW function. This is called raising an exception. When an exception is raised the exception handler blocks are searched for the one that can catch the exception. This means to find the first CATCH block that match the exception object class. This matching is done by sending the exception object the exceptionIsKindOf: message having as argument the class specified as parameter to CATCH block. If the result of this message is true then the CATCH block matches the exception.

The exceptionIsKindOf: method is implemented at the NSException class to return the result of isKindOf:. So implicitly the exceptions are grouped after their inheritance hierarchy. Some specific exception classes could implement the exceptionIsKindOf: method and simulate a graph inheritance, which is like the multiple inheritance in C++.

Inside the CATCH and OTHERWISE blocks you have one hidden parameter, the exception object, which has the name localException. You can do the following actions inside an exception handler:

  * you can go immediately after the END_CATCH statement if it does not issue any of RETURN or RETRY statements

  * you can reraise the exception by issuing the RERAISE if you want to generate an exception with the same object, or you can use THROW to generate an exception with a different object

You cannot execute a jump with the goto statement from the TRY, CATCH or OTHERWISE blocks outside them. These jumps are permitted only locally in the block. Also, do not return from TRY or CATCH blocks with ordinary return statements.

You can jump outside the TRY block with the BREAK statement that will go to the first statement following the END_CATCH statement.

Another construction allows you to specify a block of code that will be executed when an exception is caught by an upper exception handler. This allows you to do some cleanup, for example to release all the resources acquired from the system (such as memory allocation or file descriptors). This block is introduced by the CLEANUP label.

Another construction is the FINALLY block. It is equivalent with the finally block in Java. The code inside this block is called whenever either an exception is raised and caught by an upper handler or when the code inside a TRY block runs successfully.

The FINALLY construct is equivalent with the following CLEANUP construct:

     TRY {
         some code that can generate an exception
     } END_TRY
     ...
     CLEANUP {
         sequence of code
     }
     END_CATCH
     the same sequence of code from inside the CLEANUP block

If several exception handlers are nested the order in which the cleanup and finally blocks are called is the same with the order in which the functions containing them will normally return.

There are situations when you acquire some resources and you want to be sure that they are released in case of an exception that is caught above you in the stack frame. So you don' t need the CATCH or OTHERWISE blocks. You could simply write:

     TRY {
         some code that can generate an exception
     } END_TRY
     CLEANUP {
         code to release acquired resources
     }
     END_CATCH

You could use the FINALLY construct when the resource is acquired and also released in the same function. For example:

     acquire the resource
     TRY {
         some code that can generate an exception
     }
     FINALLY {
         code to release the resource
     }
     END_CATCH

With these constructions the exception handling macros has the following syntax:

     TRY {
         some code that can generate an exception
     } END_TRY
     CATCH(ExceptionClass1) {
         code to handle an exception of class ExceptionClass1
     }
     CATCH(ExceptionClass2) {
         code to handle an exception of class ExceptionClass2
     }
     ...
     OTHERWISE {
         catch all exceptions not handled above
     }
     CLEANUP {
         ...
     }
     FINALLY {
         ...
     }
     END_CATCH

OpenStep exceptions
===================

The OpenStep exceptions are defined in the terms of the above macros.

     #define NS_DURING	TRY

     #define NS_HANDLER \
         END_TRY \
         OTHERWISE

     #define NS_ENDHANDLER   END_CATCH

In the actual implementation you can also use the NS_VALRETURN and NS_VOIDRETURN macros inside the TRY block, respectively inside NS_DURING block.

When you use NS_VALRETURN or NS_VOIDRETURN macros inside a TRY block, be aware that before the function returns, the code inside all FINALLY blocks associated with the TRY block are executed first. However, because of a bug in the GNU compiler that causes the compiler to crash when it compiles Objective-C programs with nested functions for the NeXT runtime, this behavior is not implemented for the programs compiled with the NeXT runtime.

Garbage collecting
******************

Starting with version 0.9.0, libFoundation comes with two garbage collecting mechanisms that provide you with the ability to solve the memory management problem.

The first garbage collector works with the default memory management policy in OpenStep, the reference counting model. Reference counting is a simple model for keeping track of objects and works good enough unless you have cyclic data structures in your program, aka graphs of objects. These cyclic graphs of objects cannot be collected by the normal reference counting mechanism provided by OpenStep Foundation. libFoundation comes with a garbage collector based on reference counting, that's fully integrated with the reference counting model in OpenStep Foundation.

While reference counting is a simple and good technique for small to medium programs, it's usually hard to write programs using it because, as every human activity, is error-prone. The programmer can easily forget to retain or release an object, thus leading to memory leaks. A true garbage collector would solve the problem and would release the programmer from manually keeping track of the allocated memory. libFoundation comes with support for Boehm's garbage collector, a conservative collector available from http://reality.sgi.com/boehm_mti/gc.html.

There is only one source tree for the both versions of the library, the normal OpenStep compatibility library and the support for the Boehm's garbage collector library. To build the last type of library you just have to type:

       $ make gc=yes

This will build and install the library in a separate directory in the GNUstep system tree. For all the GNUstep package that you want to run in a garbage collected environment you will have to add gc=yes as an additional argument to make.

The next chapter present the garbage collector based on reference counting. The classes and protocols presented here are only useful when the garbage collector based on reference counting is used.

Garbage collector based on reference counting
=============================================

libFoundation contains some classes that allow you to write code without explicitly managing cyclic references between objects. Usually you have to manage explicitly the reference counts when you have objects that form cyclic graphs.

The garbage collector neither maintains explicitly all the pointers in your program nor it collects all the memory allocated by you in the program. Instead it collects and maintains only some special kind of objects, that are garbage collectable.

The algorithm was inspired from a similar one found in the OATH C++ library written by Brian M. Kennedy's bmk@csc.ti.com. It works in three passes. Suppose that all the objects that are garbage collectable are known. Also each object has an additional flag, used for determining if the object was already visited.

During the first pass, all objects that are garbage collectable clears the associated flag and receive the message -gcDecrementRefCountOfContainedObjects. In this method the object decrements the reference count of every garbage collectable object it contains. After this pass all the objects that have the reference count 0 are part of cyclic graphs. Such objects have their reference count due only to another objects from graph.

In the second pass we have to restore the original reference counts and to isolate the nodes from cyclic graphs. In this pass all the objects that have the reference count greater than 0 receive the message -gcIncrementRefCountOfContainedObjects. In this method the object check the flag if it's set. This flag tells if the object was visited previously. If the flag is set, the method returns, else the flag is set. Then the reference count of every garbage collectable object contained is incremented and the message -gcIncrementRefCountOfContainedObjects is sent to those objects.

After this pass all the objects that are reachable from `outside' have their reference count greater than 0. All the objects that still have their reference count equal with 0 are part of cyclic graphs and there is no reference from `outside' to an object from these graphs.

In the third pass all the objects that have their reference count equal with 0 receive the -dealloc message. In this method the objects should send the -release message to all contained objects that are not garbage collectable. This because the order of deallocation is not known and you can send -release to an already deallocated object. So if a class contains both normal objects and garbage collectable objects, it should maintain their collectable status when the objects are retained.

The GarbageCollector class
--------------------------

The class GarbageCollector implements the garbage collector. It has the following interface:

     @interface GarbageCollector : NSObject

     + (void)addObject:(id)anObject;
     + (void)objectWillBeDeallocated:(id)anObject;

     + (void)collectGarbages;

     @end

A new garbage collectable object has to be made know to the GarbageCollector collector by sending it the +addObject: message with self as argument. When the object is deallocated it should inform the GarbageCollector class about this by sending it the +objectWillBeDeallocated: message with self as argument.

The +collectGarbages should be send to the GarbageCollector class to collect the garbages. You can send it whenever you want. If you are using a run loop in your program you can set a timer to be called periodically. Or you can call the garbage collector when the program is idle.

In the current implementation the garbage collector is not thread-safe, so please don't use it in multi-threaded programs, unless you use garbage collectable objects only in one thread.

The GarbageCollecting protocol
------------------------------

To allow instances of a class to be garbage collectable, the class should implement the following protocol:

     @protocol GarbageCollecting

     - gcSetNextObject:(id)anObject;
     - gcSetPreviousObject:(id)anObject;
     - (id)gcNextObject;
     - (id)gcPreviousObject;

     - (void)gcIncrementRefCount;
     - (void)gcDecrementRefCount;

     - (void)gcDecrementRefCountOfContainedObjects;
     - (BOOL)gcIncrementRefCountOfContainedObjects;

     - (BOOL)isGarbageCollectable;

     @end

The GarbageCollector class uses a double linked list to maintain the objects. The gcSetNextObject:, gcSetPreviousObject:, gcNextObject and gcPreviousObject are used by the collector to add or remove objects in its list. This could change in the future.

The gcIncrementRefCount and gcDecrementRefCount methods should increment, respectively decrement the reference count of receiver.

The gcDecrementRefCountOfContainedObjects method should decrement the reference count of all garbage collectable objects contained, by sending them the message -gcDecrementRefCount to them.

The gcIncrementRefCountOfContainedObjects method should check the flag. If this is true, the method should return NO; it this is false the method should set it. Then it should increment the reference count of garbage collectable objects contained by sending them the -gcIncrementRefCount message. After this it should send the -gcIncrementRefCountOfContainedObjects message to the same objects. Then it should return YES.

The object should respond YES at the -isGarbageCollectable message if it is garbage collectable. The NSObject class responds NO to this message.

You should note the asymmetry between the gcDecrementRefCountOfContainedObjects and gcIncrementRefCountOfContainedObjects methods. This makes the algorithm to work. So be careful if you're using copy/paste operations to write them in your editor :-)!

Support classes
---------------

There is a class GCObject from which you could inherit your own classes. This class implements the GarbageCollecting protocol.

Using this class, you could write a class whose instances hold other objects. This class is safe to cyclic references. Here is its implementation:

     @interface MyGCObject : GCObject
     {
         id object;
         BOOL isGarbageCollectable;
     }

     - (void)setObject:(id)anObject;
     - (id)object;

     @end

     @implementation MyGCObject

     - (void)setObject:(id)anObject
     {
         [anObject retain];
         [object release];
         object = anObject;
         isGarbageCollectable = [object isGarbageCollectable];
     }

     - (id)object
     {
         return object;
     }

     - (void)decrementRefCountOfContainedObjects
     {
         [object gcDecrementRefCount];
     }

     - (BOOL)incrementRefCountOfContainedObjects
     {
         if(![super incrementRefCountOfContainedObjects])
             return NO;
         [object gcIncrementRefCount];
         [object incrementRefCountOfContainedObjects];
         return YES;
     }

     - (void)dealloc
     {
         if(!isGarbageCollectable)
             [object release];
         [super dealloc];
     }

     @end

There are also concrete subclasses of NSArray and NSDictionary named GCArray and GCDictionary respectively, together with their mutable classes GCMutableArray and GCMutableDictionary. Their instances could hold both normal and garbage collectable objects.

Boehm's garbage collector
=========================

Starting with version 0.9.0 libFoundation comes with support for the Boehm's garbage collector. It is available from

http://reality.sgi.com/boehm_mti/gc.html

It is a conservative garbage collector that works by replacing the system memory allocation routines (malloc/calloc/realloc) with the ones that come with the collector. The memory allocation works as before, you allocate memory using the GC_malloc() function instead of malloc(), GC_calloc() instead of calloc() and GC_realloc() instead of realloc(). The difference comes from the fact that you're no longer required to call a free function. The collector takes care of no longer reachable portions of the allocated memory by monitoring the memory allocation of your program and trying to collect the garbages when certain conditions are met. You can also explicitly invoke the collection the garbages by calling the GC_collect() function.

The collection can also occur in another thread on systems that support multi-threading. You can disable the collection in the main thread by setting the value of a variable (GC_dont_gc) and invoke the collection in a separate thread when you wish, perhaps on a time basis or when some other conditions are met.

Another feature is that the collection can be done incrementally, ie not all the memory is collected at once. This can be done by calling the GC_collect_a_little() function. One can use this feature in the program's run loop of an interactive program to make sure the collection will not make the program stop while the collection is in progress.

Memory allocation functions are described in gc.h.

Atomic memory allocation
------------------------

The Boehm's garbage collector normally assumes that all the memory allocated potentially contains pointers. However this is not always true. For memory zones that one knows they don't contain pointers to other allocated memory, the GC_malloc_atomic() can be used. This function marks the returned memory zone as not containing any pointer. Use this function for allocating strings and memory zones that does not contain pointers.

Typed memory allocation
-----------------------

There are many cases when the allocated memory may contain both data and pointers. In this case the memory can be allocated using the normal GC_malloc() function and let the collector assume that all the contained data are pointers. This is both inefficient and error-prone because it is possible, even with a small probability, that integers have the same value as an existing pointer, thus keeping a reference to a memory zone and preventing it to be deallocated.

Fortunately there's a better approach for this. At the time of the allocation, it is possible to inform the collector where the pointers are located inside it. This mechanism is called typed memory.

To describe a memory zone a descriptor of it has to be constructed first. The GC_make_descriptor() function is used for this; it takes as arguments a bitmap describing the memory zone and the number of meaningful bits in the bitmap. The less signifiant bit in the bitmap corresponds to the first word in the memory zone.

The descriptor returned by the GC_make_descriptor() function is then passed to the GC_malloc_explicitly_typed() or GC_calloc_explicitly_typed()functions to allocate a memory zone. One caveat though, the memory returned by these functions cannot be reallocated at a later point in time.

The typed memory functions have their prototypes in the gc_typed.h file.

Finalization
------------

The Boehm's collector provides a facility that allows a function to be called just before a memory zone is collected. The GC_register_finalizer() takes as arguments the function to be called when the memory zone is being collected, the address of the memory zone, a client data that's passed to the function when it is called together with the address of the memory zone. There two more arguments to this function, that are used as out arguments: the old finalizer function and the old client data. Pass NULL to these arguments if you're not interested in their values.

Be careful with what you do in the finalizer function. In general don't assume that the finalizers are invoked in any particular order. More important don't do any memory allocation inside the finalizer function. This would case the finalizer to be invoked again which is not probably what you want (this may be a bug in the collector).

More explanation for the public functions can be found in both gc.h and gc_typed.h.

Boehm's garbage collector support in the GNU Objective-C compiler and runtime
-----------------------------------------------------------------------------

The GNU Objective-C runtime and compiler have been enhanced to support the Boehm's garbage collector. To gain speed and to be able to implement some special facilities like weak pointers (pointers that are invisible to the garbage collector), the GNU Objective-C runtime uses typed memory to allocate all the instances of the classes.

The typed memory descriptor for each class is computed once per class, immediately after the object has been initialized. The descriptor is computed from the information about instance variables available in the class. To correctly handle all the type information, the Objective-C encoding for bitfields has been changed to include description of the type holding the bitfield and the position of the bitfield inside the corresponding value.

To mark a pointer inside an instance as a weak pointer, the function class_ivar_set_gcinvisible() from the GNU runtime should be used. This function takes as argument the class whose instances contain the weak pointer, the name of the instance variable and a boolean flag that marks or unmarks the instance variable as a weak pointer.

See the documentation in the GNU Objective-C compiler for a description of the new encoding of bitfields and for an example of the class_ivar_set_gcinvisible() function.

Boehm's garbage collector support in libFoundation
--------------------------------------------------

libFoundation hides a lot of the interface with the Boehm's garbage collector by providing the same API for the memory management functions no matter what is the model used, the reference counting mechanism or the Boehm's garbage collector.

The objects are allocated by the library using the normal NSAllocateObject() function. In the case of Boehm's garbage collector a typed memory object is properly allocated.

Internally the memory allocation for things other than objects is performed using the Malloc, Calloc, Realloc and Free inline functions. There are also versions that are used to allocate atomic memory, MallocAtomic and CallocAtomic. These pseudo-functions are not exported but one can create similar functions for other libraries or applications.

If you need to know when a given object will be finalized, you just have to make the class adopt the GCFinalization protocol. This protocol defines a single method, -gcFinalize, that is invoked by the garbage collector when an object is about to finalize.

In addition to finalization, the GarbageCollector class provides a powerful mechanism that allows objects to be registered as observers of other objects finalization. Here are the specific methods:

     @interface GarbageCollector (BoehmGCSupport)

     + (void)registerForFinalizationObserver:(id)observer
       selector:(SEL)selector
       object:(id)object;
     + (void)unregisterObserver:(id)observer
       forObjectFinalization:(id)object;

     @end

When the observer object is registered for observing the finalization of object, the observer's method whose selector is represented by selector is automatically called when object is about to finalize.

You can manually unregister an object as the observer of an object finalization by using the +unregisterObserver:forObjectFinalization: method. If you provide nil for the object then observer will be unregistered for all the objects it has been previously registered as observer.

If an object registered as observer of another objects finalizes, the GarbageCollector class automatically unregisters the observer for all the objects it was observer. You don't have to take any special actions to remove the observer except if it's kept in the internal structures of your program. In this case you should register another object as an observer of the original's observer finalization and remove it from your structures. As you can see an object can be simultaneously both an observed and an observer object, there's no restriction in doing this.

Useful macros
-------------

When working with the Boehm's garbage collector, the messages used by the reference counting mechanism are obsolete and they simply introduce an unnecessary overhead. That's why instead of sending the retain, release and autorelease messages you'd better use the macros with the similar names, RETAIN, RELEASE and AUTORELEASE. When the code is compiled with support for Boehm's garbage collector the correspondent messages are not sent at all.

In addition to the above macros, another macro should be used to make the code cleaner. The ASSIGN macro can be used whenever an object value is assigned to an object variable and the old value of the variable needs to be release and the new value retained. The definition of this macro is:

     #define ASSIGN(object, value) \
       ({if (value) [value retain]; \
         if (object) [object release]; \
         object = value;})

When Boehm's garbage collector is used the definition of the macro is simply:

     #define ASSIGN(object, value) \
       object = value

Another macro can be used whenever the code requires the creation of an autorelease pool. This pool is not needed when the code works in the presence of Boehm's garbage collector. The macro is CREATE_AUTORELEASE_POOL and should be used as a variable definition and must placed the last in the variables definition list. Use the RELEASE macro to release the pool.

The preprocessor define LIB_FOUNDATION_BOEHM_GC can be used to find out if the program is compiled with support for Boehm's garbage collector (see Preprocessor defines for other preprocessor defines). If you need to find out at runtime if the program was compiled with support for Boehm's collector you can access the read-only variable _usesBoehmGC.

The NSZone class and memory allocation
**************************************

Object allocation is performed from zones that group related objects in a zone of memory. A zone is represented in libFoundation by an instance of a subclass of NSZone. A zone is an object that not only keeps the memory zone from which the objects are allocated, but also encapsulates the algorithms that manage the memory allocation from that zone.

Traditionally, NSZone is implemented as a structure. In libFoundation, NSZone is a class instead of a struct, and the related zone functions are static inline functions that invoke the corresponding methods of the zone instance. The idea behind the definition of the NSZone as a class and not as a struct is to offer the user of the library the possibility to build his own allocator and to let current and future allocators coexist.

Currently three zones are available: NSDefaultZone, NSAllocDebugZone and StackZone. The first two they can be used only through the NSZone class and not directly. When libFoundation is compiled with support for the Boehm's garbage collector the allocation is done using only the collector's allocation functions and the entire mechanism described below for the NSZone classes is completely unused.

When the program first starts a default zone is created automatically. This zone is either an instance of the NSDefaultZone or of the NSAllocDebugZone class, depending on the mode in which the program is run. If the program runs using the reference counting mechanism, the environment variable ALLOCDEBUG is checked. If the variable exists in your environment then the default zone will be an instance of NSAllocDebugZone. If this environment variable is not defined then an instance of NSDefaultZone becomes the default zone. If the program runs using the Boehm's garbage collector, no zones are used; for more information see Zones and garbage collection.

You can change the default zone from which the future objects will be allocated using the setDefaultZone: method. To do this you have to create an instance of the zone you want to allocate objects from and call the +setDefaultZone: method of NSZone with the new instance. The zones are kept into a stack, the most recent zone being passed to setDefaultZone: being the top of the stack. When you release a zone and it has to be deallocated, the zone is removed from the stack of zones. If the zone object happens to be the top of the stack, the zone under it becomes the new default zone.

The NSZone class
================

NSZone is an abstract class that defines the basic behavior for all the memory allocators.

  * +(void)setDefaultZone:(NSZone*)zone;

          Sets the default zone from which the subsequent memory allocation takes place.

  * +(NSZone*)defaultZone;

          Returns the default zone.

  * +(NSZone*)zoneFromPointer:(void*)pointer;

          Returns the zone from which pointer was allocated. Care should be taken as the zones are asked (using -pointerInZone:) in order if the pointer was allocated by them. See the -pointerInZone: method description for more information.

  * +(BOOL)checkZone;

          Check the memory allocated by all the zones. See the -checkZone method description for more information.

  * +(id)allocZoneInstance;

          This is the low level method used to allocate a zone instance. This is used because allocation of zone instances is done in a special way to avoid the chicken and egg problem (from which zone a zone instance is allocated?)

  * -(id)initForSize:(unsigned)startSize granularity:(unsigned)granularity
      canFree:(BOOL)canFree;

          This is the designated initialization method. Creates a zone that can allocate as much as startSize memory initially. The memory can grow or shrink in increments of granularity. If canFree is set to YES the memory is freed when when -free: is sent, otherwise the memory is never freed.

  * -(void*)malloc:(unsigned)size;

          Allocate a memory zone of size bytes and return it. Returns NULL if this is not possible.

  * -(void*)mallocAtomic:(unsigned)size;

          Similar with -malloc: but allocate a memory zone that's not searched by the garbage collector for pointers.

  * -(void*)calloc:(unsigned)numElems byteSize:(unsigned)byteSize;

          Allocate a memory zone that holds numElems elements, each of byteSize, set all the bytes in it to 0 and return it. Returns NULL if the allocation fails.

  * -(void*)callocAtomic:(unsigned)numElems byteSize:(unsigned)byteSize;

          Similar with -calloc:byteSize: but return a memory zone that's not searched by the garbage collector for pointers.

  * -(void*)realloc:(void*)pointer size:(unsigned)size;

          Grow or shrink the size of the memory zone pointed to by pointer to have the new size size.

  * -(void)recycle;

          Frees the receiving zone after adding the still alive allocated zones to the default zone. Currently there are no zones in libFoundation that implement this algorithm.

  * -(BOOL)pointerInZone:(void*)pointer;

          Returns YES if pointer points to a memory zone allocated by the receiving zone. Some zones are not able to reliably determine if the pointer is theirs or not. For example NSDefaultZone always returns true since few libc malloc implementation provide the capability to identify if a pointer is valid or not.

  * -(void)freePointer:(void*)pointer;

          If the zone was initialized to free pointers, free the memory zone pointed to by pointer. Otherwise do nothing.

  * -(void)setName:(NSString*)name;

          Set the name of the receiving zone.

  * -(NSString*)name;

          Return the name of the receiving zone.

  * -(BOOL)checkZone;

          Checks the consistency of the memory allocated by the zone. Some classes, notably NSAllocDebugZone, when you request memory from them, they allocate more memory that is marked in a special way. In -checkZone they check if the marked zones are altered in which case they output an error message.

The NSZone functions
====================

The OpenStep specification defines several functions that deal with zones. In libFoundation these functions are implemented as inline functions that send the corresponding message to the zone instance or directly to the NSZone class. The correspondency between them is straightforward so check the method description for more information.

Here are the functions used to manipulate a zone:

  * NSZone* NSCreateZone(unsigned startSize, unsigned granularity, BOOL canFree);

  * NSZone* NSDefaultMallocZone(void);

  * NSZone* NSZoneFromPointer(void* pointer);

  * void* NSZoneMalloc(NSZone* zone, unsigned size);

  * void* NSZoneMallocAtomic(NSZone* zone, unsigned size);

  * void* NSZoneCalloc(NSZone* zone, unsigned numElems, unsigned byteSize);

  * void* NSZoneCallocAtomic(NSZone* zone, unsigned numElems,
      unsigned byteSize);

  * void* NSZoneRealloc(NSZone* zone, void* pointer, unsigned size);

  * void NSZoneFree(NSZone* zone, void* pointer);

  * void NSRecycleZone(NSZone* zone);

  * void NSSetZoneName(NSZone* zone, NSString* name);

  * NSString* NSZoneName(NSZone* zone);

The NSAllocDebugZone class
==========================

The NSDefaultZone uses system malloc, calloc, realloc and free directly, without any checks.

The NSAllocDebugZone is used to help in tracking down memory allocation bugs. It provides the following features:

  * check double deallocation for pointers

  * check deallocation of non-existing pointers

  * use a block of memory past its margins

  * list blocks allocated since a moment (marked by a special call)

  * each allocated pointer has a serial number

  * stop when alloc-ing a pointer with a certain serial number

  * do SYSTEM_MALLOC_CHECK and internal checks every count operation

  * be able to control things from gdb

  * be able to control things from environment variables

The NSAllocDebugZone is controlled by the following environment variables:

  * ALLOCDEBUG: must be set to something to use the alloc debug zone

  * ALLOCDEBUG_STOP: stop in debugger SIGINT when alloc-ing pointer with given serial number (this serial number is reported when and error with that pointer occurs). Undefined or 0 means no stop.

  * ALLOCDEBUG_COUNT: number of passes inside allocation/deallocation functions to SYSTEM_MALLOC_CHECK and internal check. Undefined or 0 means no checks.

  * ALLOCDEBUG_UPPER and ALLOCDEBUG_LOWER: number of bytes to alloc at top/bottom of object block. These bytes are set to a given value (0x88) and checked at free and internal check to guard against using memory past the limit. Undefined or zero means no margin. Note that this size must be multiples of the machine address alignment (4, 8, 16 are recommended values).

The NSAllocDebugZone provides these functions to be used from the GNU debugger.

  * debuggerStopMark(unsigned mark): overrides ALLOCDEBUG_STOP

  * debuggerCheckTime(unsigned count): overrides ALLOCDEBUG_COUNT

  * debuggerDescription(id obj): performs printf("%s\n", [obj description])

  * debuggerPerform(id obj, char* sel): performs [obj sel]

  * debuggerPerformWith(id obj, char* sel, id arg): performs

     [obj sel:(id)atoi(arg)]

The program instantiates two zones: one NSDefaultZone and one NSAllocDebugZone, and uses one or the other depending on the ALLOCDEBUG environment variable. If this variable exists in your environment then the NSAllocDebugZone instance will be used.

Below are some setting you might find useful when working with the NSAllocDebugZone class.

     # must be set to something to use alloc debug zone
     ALLOCDEBUG=YES
     export ALLOCDEBUG=YES

     # stop in debugger (SIGINT) when alloc-ing pointer number *
     # nil or 0 means no stop
     ALLOCDEBUG_STOP=0
     export ALLOCDEBUG_STOP

     # stop in debugger (SIGINT) when alloc-ing pointer number *
     # nil or 0 means no stop
     ALLOCDEBUG_MARK=0
     export ALLOCDEBUG_MARK

     # number of passes inside allocation/deallocation functions
     # to SYSTEM_MALLOC_CHECK and internal check
     # nil or 0 means no checks
     ALLOCDEBUG_COUNT=16
     export ALLOCDEBUG_COUNT

     # number of bytes to alloc at top/bottom of object block
     # these bytes are set to a given value (0x88) and checked
     # at free and internal check to guard against using memory
     # past the limit.
     ALLOCDEBUG_UPPER=8
     ALLOCDEBUG_LOWER=8
     export ALLOCDEBUG_UPPER ALLOCDEBUG_LOWER

Zones and garbage collection
============================

The zone mechanism provides a way to group related pointers in a program.  For example different portions of an application which do not have much in common, can use different zones. This improves the memory localization in the virtual memory system of the operating system and lowers the mapping in and out of the memory pages.

In the current implementation, both garbage collectors, the Boehm's collector and the one based on reference counting, do not take advantage of this behavior. When a collection starts searching for the unused pointers can spread over all the existing zones.

Because of this, when libFoundation is compiled with support for the Boehm's collector, the zones are completely disabled. The NSZone functions that perform memory allocation simply invoke the collector's functions.

Features of the NSInvocation class
**********************************

The ability to dynamically construct method invocations is an important feature in Objective-C libraries. This ability is used by various applications like distributed objects and various language interpreters to provide interface with the native methods or functions. In libFoundation the NSInvocation class is designed to provide this important facility.

In the OpenStep specification and some OpenStep Foundation implementations, the NSInvocation class is only used to encapsulate the arguments and return value of a forwarded message and to allow sending a different message in the context of the forwarding. The normal usage of the NSInvocation is in the -forwardInvocation: method:

     - (void)forwardInvocation:(NSInvocation*)anInvocation
     {
         [anInvocation setTarget:anotherObject];
         [anInvocation setSelector:anotherSelector];
         [anInvocation invoke];
     }

In this example the NSInvocation object is created automatically by the Foundation library, with the help of the Objective-C runtime library, when a message is sent to an object that does not implement it. The actual implementation assumes the stack frame for the arguments of the method already exists  (On many systems this is only a partial picture, because the native convention calls can also use registers to pass arguments to a function.). All the further changes to the method's arguments using the NSInvocation's methods are performed on that stack frame. After the method invocation returns you can access the return value and possibly change it, using the getReturnValue: and setReturnValue: methods.

The situation is different when you build a dynamic method invocation.

         BOOL flag = YES;
         int anInt = 1234;
         float aFloat = 12345.0;
         double aDouble = 98765.0;
         id invocation = [[NSInvocation new] autorelease];

         [invocation setSelector:
                     @selector(setFlag:intValue:floatValue:doubleValue:)];
         [invocation setTarget:object];
         [invocation setArgument:&flag atIndex:2];
         [invocation setArgument:&anInt atIndex:3];
         [invocation setArgument:&aFloat atIndex:4];
         [invocation setArgument:&aDouble atIndex:5];
         [invocation invoke];

In this example the dynamic method invocation is constructed from scratch, by providing the object, the message selector and the arguments of the message. Then you can invoke the message and, after the message returns, you can access the return value.

It is very important to set the target and selector before setting the arguments. The NSInvocation is not otherwise able to construct the stack and registers frame and set the arguments of the method invocation.

Porting NSInvocation
====================

The NSInvocation is highly dependent on the target machine. The code that depends on the target machine is carefully separated from the independent part of the class. This code is written as macros in the config/processor/operating-system.

NSInvocation is implemented using the __builtin_apply and __builtin_return built-in pseudo-functions that are available in the GNU C compiler. See the GNU C compiler documentation of these functions.

The following macros have to be defined for a given target machine. Defining them is a though process, they closely follow the native convention calls defined for the target in the GCC target dependent files. We intend to take advantage of the knowledge that's already in the compiler and move the NSInvocation's code into the Objective-C runtime library.

  * FUNCTION_VALUE

  * FUNCTION_SET_VALUE

  * GET_STRUCT_VALUE_ADDRESS

  * SET_STRUCT_VALUE_ADDRESS

In addition, if the target system does not work as expected copying the arguments onto and from the __builtin_apply's frame, you can define in addition the FRAME_SET_ARGUMENT and FRAME_GET_ARGUMENT macros.

FUNCTION_VALUE should copy the return value from the result frame returned by the __builtin_apply pseudo-function into a memory zone received as argument. This macro has the following arguments:

  * TYPE (char*): the Objective-C encoding of the return value type

  * ARGS (void*): the arguments frame passed to __builtin_apply

  * RESULT_FRAME (void*): the result frame returned by __builtin_apply

  * RETURN_VALUE (void*): the memory zone where the value should be set. This zone is already allocated.

FUNCTION_SET_VALUE should set the return value into the result frame returned by the __builtin_apply. It has the following arguments:

  * TYPE (char*): the Objective-C encoding of the return value type

  * ARGS (void*): the arguments frame passed to __builtin_apply

  * RESULT_FRAME (void*): the result frame returned by __builtin_apply

  * RETURN_VALUE (void*): the memory zone where the returned value should be copied from.

GET_STRUCT_VALUE_ADDRESS is an expression that should produce the return value address in the case this is returned by reference or NULL if the return value is not returned by reference. Usually only the aggregates (structures and unions) are returned by reference. This macro has the following arguments:

  * ARGS (void*): the arguments frame passed to __builtin_apply. Usually the address of return value is set here by the __builtin_apply_args pseudo-function

  * RETTYPE (char*): the Objective-C encoding of the return value type.

SET_STRUCT_VALUE_ADDRESS should set in the arguments frame that will be passed to __builtin_apply the address of the return value if this is returned by reference. The arguments are:

  * ARGS (void*): the arguments frame that will be passed to __builtin_apply

  * ADDR (void*): the address of the zone where the called function should set the return value. This zone is already allocated.

  * RETTYPE (char*): the Objective-C encoding of the return value type

FRAME_SET_ARGUMENT should be used whenever the default mechanism of copying the argument onto the __builtin_apply's frame is not working. The default mechanism is implemented in the NSInvocation's -setArgument:atIndex: method. If you do not define this macro the default mechanism is used.

The arguments of this macro are:

  * FRAME_DATA (void*): The address in the __builtin_apply's frame where the argument's value has to be copied.

     ARGUMENT_LOCATION (void*): The address where the argument to be copied is located.

     ARG_INFO (NSArgumentInfo): Describes the type of the argument.

The FRAME_GET_ARGUMENT macros is similar with FRAME_SET_ARGUMENT but does the opposite job.

For an example of how the above macros are implemented you can take a look in the config directory in the libFoundation's distribution.

Features of the NSMethodSignature class
***************************************

NSMethodSignature provides information about the type signature of a method. The Objective-C type encoding of a method is a C string that contains an encoding of the return value type and type of the arguments including information about how to access them on the stack and registers frames. See the Objective-C documentation in the GCC runtime for more information about method type encoding.

Below is an example of how to create a NSMethodSignature instance for a given method of an object:

         id anObject;
         struct objc_method* mth
              = class_get_instance_method(self->isa, aSelector);
         const char* types = mth->method_types;
         id signature = [NSMethodSignature signatureWithObjCTypes:types];

The above code is implemented by the NSObject's methodSignatureForSelector: method. If you send this method to a class, the method searches for a class method whose selector is the same as the argument. If the message is sent to an instance, the method searches for an instance method. If you don't want to create an instance of a class just to find out what is the signature of an instance method, you can use the instanceMethodForSelector: method, that searches in the class for an instance method with the same selector as the argument.

In addition to providing information about already existing method encodings that are available for compiled methods, the NSMethodSignature class from libFoundation allows you to construct method signatures for new methods, that could be created for example by an interpreter. Suppose one wants to create a method encoding that has arguments an integer and its return type is void; you can do like this:

         id signature = [NSMethodSignature signatureWithObjCTypes:"vi"];

The NSMethodSignature class computes the full signature that contains the offsets of the arguments on the stack and registers frames. This code is dependent on the target machine so the result may be different between various processors and even on the same processor but different OSes.

Porting NSMethodSignature
=========================

Porting NSMethodSignature implies defining the below macros, similar with the way NSInvocation is ported to a new platform. As with the NSInvocation's macros, this code will probably also move in the Objective-C runtime library, to take advantage of the compiler's knowledge on the target system.

  * CUMULATIVE_ARGS

  * INIT_CUMULATIVE_ARGS

  * FUNCTION_ARG_ENCODING

The name of this macros are the same with the similar ones from the GNU CC compiler. However they don't correspond neither in semantics nor in the argument types.

CUMULATIVE_ARGS is the data type of a variable used to hold about arguments processed so far. On a machine where all the arguments are passed on stack, this type is usually int.

INIT_CUMULATIVE_ARGS should initialize the variable of type CUMULATIVE_ARGS described above.

FUNCTION_ARG_ENCODING determines the encoding of the next argument of a method. It must produce a NSString describing the Objective-C encoding and position of the argument in the arguments frame of the method.

If you want to determine how to write the encoding for a new machine you could use the program generated by signature-test.pl perl script in FoundationTestsuite. This generates a class with a lot of methods. You can look at the output of the program to see how the compiler encodes the methods. Also take a look in the objc-act.c file in the compiler to see how the methods are encoded.