libobjc2 but not gatekept by cmake
You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
David Chisnall 4891eb9d5f Document a bit more of class structure and of type encodings. 8 years ago
ABIDoc Document a bit more of class structure and of type encodings. 8 years ago
CMake Improve detection of libsupc++ 8 years ago
Test Add missing file. 8 years ago
objc Document a bit more of class structure and of type encodings. 8 years ago
.gitignore Add .gitignore. 11 years ago
.travis.yml Enable Travis testing on OS X. 10 years ago
ANNOUNCE Add a warning to the announcement. 8 years ago
ANNOUNCE.1.0 Added 1.1 announcement. Committed some work-in-progress clang-specific build stuff (don't use this, it doesn't work correctly yet). 15 years ago
ANNOUNCE.1.1 Added 1.1 announcement. Committed some work-in-progress clang-specific build stuff (don't use this, it doesn't work correctly yet). 15 years ago
ANNOUNCE.1.2 Added 1.2 release announcement. 15 years ago
ANNOUNCE.1.3 Added note about aliases to release announcement. 15 years ago
ANNOUNCE.1.4 Created 1.4 release announcement. 15 years ago
ANNOUNCE.1.5 s/fifth/sixth 15 years ago
ANNOUNCE.1.6 1.6 release announcement. 14 years ago
ANNOUNCE.1.6.1 Archive 1.6.1 release announcement. 14 years ago
ANNOUNCE.1.7 Fixed svn URL for 1.7 release announcement. 13 years ago
ANNOUNCE.1.8 Fix copy and paste error in release announcement. 11 years ago
ANNOUNCE.1.8.1 Added 1.8.1 release announcement to master branch. 11 years ago
API Added property_getName(). Added non-portable API documentation. 16 years ago
CMakeLists.txt Remove low memory profile. 8 years ago
COPYING Removed last bits of legacy code from libobjc2. Added new exception handling implementation. 16 years ago
INSTALL add assembler flags needed for cmake 13 years ago
NSBlocks.m Remove separate flags for class and metaclass. 8 years ago
Protocol2.m Add support for improved property structure. 8 years ago
README.md Trivial change to hopefully poke Travis into working. 10 years ago
abi_version.c Small object + ARC tweaks. 15 years ago
alias.h Implement a hook that allows the compiler to register the aliases used with the 15 years ago
alias_table.c Look up the class name when registering an alias. 8 years ago
arc.m Fix a bug in weak ref handling. 8 years ago
asmconstants.h Rework slot handling so that the fields that are used for dispatch are 10 years ago
associate.m Remove separate flags for class and metaclass. 8 years ago
block_to_imp.c Check for Thumb-2 more explicitly. 10 years ago
block_trampolines.S Check for Thumb-2 more explicitly. 10 years ago
blocks_runtime.h Add objc/blocks_private.h header to expose some internals of the blocks runtime 14 years ago
blocks_runtime.m Fix block refcounts to use saturating arithmetic. 8 years ago
buffer.h Allow the buffered objects to be something other than a pointer. 10 years ago
caps.c Added support for tracing message sends to the runtime. 13 years ago
category.h Rename legacy types. 8 years ago
category_loader.c Checkpoint more work on new ABI. 8 years ago
class.h Whitespace. 8 years ago
class_table.c Rename method_list.h to method.h 8 years ago
cmake_uninstall.cmake.in Add uninstall target to CMake. 13 years ago
common.S Only use .type on ELF targets. 13 years ago
constant_string.h Stop treating NSObject as magic and do what OS X does with regard to root objects and metaclasses. 15 years ago
dtable.c Rename method_list.h to method.h 8 years ago
dtable.h Ensure that objects that support ARC will use ARC, even if they are 10 years ago
dwarf_eh.h (Hopefully) fix C++ exception interop on ARM. 10 years ago
eh_personality.c Small cleanups. 8 years ago
encoding2.c Rename method_list.h to method.h 8 years ago
gc_boehm.c Audit the runtime for direct access to variable-sized arrays. 8 years ago
gc_none.c Fix the build with GC enabled, export the GC symbols in all build configurations. 13 years ago
gc_ops.h Fix malloc() / free() imbalance. 15 years ago
hash_table.c If we're linking against Boehm GC, then we may as well allow it to collect the runtime's hash tables, rather than doing that manually. 15 years ago
hash_table.h Fix two small bugs in the hopscotch hash that meant that moving elements near the end of the array sometimes caused them to become lost. 10 years ago
hooks.c Added support for tracing message sends to the runtime. 13 years ago
ivar.c Modify ivar flags. 8 years ago
ivar.h Finish documenting instance variables. 8 years ago
legacy.c Modify ivar flags. 8 years ago
legacy.h Rename legacy types. 8 years ago
legacy_malloc.c libobjc2: tweaks to build on Windows 16 years ago
loader.c Add support for improved property structure. 8 years ago
loader.h Rename method_list.h to method.h 8 years ago
lock.h Add explicit cast for pthread lock initialiser. 13 years ago
method.h Add method markers. 8 years ago
module.h Change [1] to [] for variable length structure elements (C99 - silences array out of bounds errors). 15 years ago
mutation.m Fix enumeration mutation function prototype to match what clang expects (id instead of void* argument). 15 years ago
nsobject.h Added support for associative references. Modified sync code to use this. 15 years ago
objc_msgSend.S Add objc_msgSend for AArch64. 10 years ago
objc_msgSend.aarch64.S Use the correct compare instruction. 10 years ago
objc_msgSend.arm.S Don’t use a NEON instruction on ARM variants that don’t have NEON. 10 years ago
objc_msgSend.mips.S Use register names that don't make LLVM whine, rather than the correct 10 years ago
objc_msgSend.x86-32.S Fix x86-32 objc_msgSend for new sarray structure. 10 years ago
objc_msgSend.x86-64.S Fix x86-32 objc_msgSend for new sarray structure. 10 years ago
objcxx_eh.cc Fix the build with GC enabled, export the GC symbols in all build configurations. 13 years ago
objcxx_eh.h Implemented the new exception ABI, and a load of tests for it. This is used by 13 years ago
pool.h Print some memory usage statistics on exit if LIBOBJC_MEMORY_PROFILE is 13 years ago
properties.h Document a bit more of class structure and of type encodings. 8 years ago
properties.m Remove separate flags for class and metaclass. 8 years ago
protocol.c Audit the runtime for direct access to variable-sized arrays. 8 years ago
protocol.h Document a bit more of class structure and of type encodings. 8 years ago
runtime.c Rename method_list.h to method.h 8 years ago
sarray2.c Move the data for sparse arrays into the tree structure. 10 years ago
sarray2.h Fix typo in comment. 10 years ago
selector.h Initial start of documenting the ABI. 8 years ago
selector_table.c Rename method_list.h to method.h 8 years ago
sendmsg2.c Clean up method / slot lookup interfaces. 8 years ago
slot_pool.h Refactor to use `objc_method` as the slot. 8 years ago
spinlock.h Added helper function for C++ non-POD type atomic properties. 13 years ago
statics_loader.c Allow the buffered objects to be something other than a pointer. 10 years ago
string_hash.h Implemented support for __weak with ARC. 15 years ago
toydispatch.c Move toydispatch into libobjc2. 15 years ago
type_encoding_cases.h Fix type encoding of blocks. 15 years ago
unistd.h Added a custom unistd.h to work around glibc vs Clang conflict on __block (hack taken from LanguageKit/CodeGen in Etoile) 14 years ago
unwind-arm.h Add missing declaration to ARM unwind header. 10 years ago
unwind-itanium.h Implement ARM EH support, fix objc_msgSend() to work on ARM. 14 years ago
unwind.h Implement ARM EH support, fix objc_msgSend() to work on ARM. 14 years ago
visibility.h First pass at implementing Apple-compatible GC using Boehm. Still needs some tidying, but the following work: 15 years ago

README.md

GNUstep Objective-C Runtime

Build Status

The GNUstep Objective-C runtime is designed as a drop-in replacement for the GCC runtime. It supports both a legacy and a modern ABI, allowing code compiled with old versions of GCC to be supported without requiring recompilation. The modern ABI adds the following features:

  • Non-fragile instance variables.
  • Protocol uniquing.
  • Object planes support.
  • Declared property introspection.

Both ABIs support the following feature above and beyond the GCC runtime:

  • The modern Objective-C runtime APIs, introduced with OS X 10.5.
  • Blocks (closures).
  • Low memory profile for platforms where memory usage is more important than speed.
  • Synthesised property accessors.
  • Efficient support for @synchronized()
  • Type-dependent dispatch, eliminating stack corruption from mismatched selectors.
  • Support for the associated reference APIs introduced with Mac OS X 10.6.
  • Support for the automatic reference counting APIs introduced with Mac OS X 10.7

History

Early work on the GNUstep runtime combined code from the GCC Objective-C runtime, the Étoilé Objective-C runtime, Remy Demarest's blocks runtime for OS X 10.5, and the Étoilé Objective-C 2 API compatibility framework. All of these aside from the GCC runtime were MIT licensed, although the GPL'd code present in the GCC runtime meant that the combined work had to remain under the GPL.

Since then, all of the GCC code has been removed, leaving the remaining files all MIT licensed, and allowing the entire work to be MIT licensed.

The exception handling code uses a header file implementing the generic parts of the Itanium EH ABI. This file comes from PathScale's libcxxrt. PathScale kindly allowed it to be MIT licensed for inclusion here.

Non-Fragile Instance Variables

When a class is compiled to support non-fragile instance variables, the instance_size field in the class is set to 0 - the size of the instance variables declared on that class (excluding those inherited. For example, an NSObject subclass declaring an int ivar would have its instance_size set to 0 - sizeof(int)). The offsets of each instance variable in the class's ivar_list field are then set to the offset from the start of the superclass's ivars.

When the class is loaded, the runtime library uses the size of the superclass to calculate the correct size for this new class and the correct offsets. Each instance variable should have two other variables exported as global symbols. Consider the following class:

@interface NewClass : SuperClass {
	int anIvar;
}
@end

This would have its instance_size initialized to 0-sizeof(int), and anIvar's offset initialized to 0. It should also export the following two symbols:

int __objc_ivar_offset_value_NewClass.anIvar;
int *__objc_ivar_offset_NewClass.anIvar;

The latter should point to the former or to the ivar_offset field in the ivar metadata. The former should be pointed to by the only element in the ivar_offsets array in the class structure.

In other compilation units referring to this ivar, the latter symbol should be exported as a weak symbol pointing to an internal symbol containing the compiler's guess at the ivar offset. The ivar will then work as a fragile ivar when NewClass is compiled with the old ABI. If NewClass is compiled with the new ABI, then the linker will replace the weak symbol with the version in the class's compilation unit and references which use this offset will function correctly.

If the compiler can guarantee that NewClass is compiled with the new ABI, for example if it is declared in the same compilation unit, by finding the symbol during a link-time optimization phase, or as a result of a command-line argument, then it may use the __objc_ivar_offset_value_NewClass.anIvar symbol as the ivar offset. This eliminates the need for one load for every ivar access.

Protocols

The runtime now provides a __ObjC_Protocol_Holder_Ugly_Hack class. All protocols that are referenced but not defined should be registered as categories on this class. This ensures that every protocol is registered with the runtime.

In the near future, the runtime will ensure that protocols can be looked up by name at run time and that empty protocol definitions have their fields updated to match the defined version.

Protocols have been extended to provide space for introspection on properties and optional methods. These fields only exist on protocols compiled with a compiler that supports Objective-C 2. To differentiate the two, the isa pointer for new protocols will be set to the Protocol2 class.

Blocks

The GNUstep runtime provides the run time support required for Apple's blocks (closures) extension to C. This follows the same ABI as OS X 10.6.

Fast Proxies and Cacheable Lookups

The new runtime provides two mechanisms for faster lookup. The older objc_msg_lookup() function, which returns an IMP, is still supported, however it is no longer recommended. The new lookup functions is:

Slot_t objc_msg_lookup_sender(id *receiver, SEL selector, id sender)

The receiver is passed by pointer, and so may be modified during the lookup process. The runtime itself will never modify the receiver. The following hook is provided to allow fast proxy support:

id (*objc_proxy_lookup)(id receiver, SEL op);

This function takes an object and selector as arguments and returns a new objects. The lookup will then be re-run and the final message should be sent to the new object.

The returned Slot_t from the new lookup function is a pointer to a structure which contains both an IMP and a version (among other things). The version is incremented every time the method is overridden, allowing this to be cached by the caller. User code wishing to perform IMP caching may use the old mechanism if it can guarantee that the IMP will not change between calls, or the newer mechanism. Note that a modern compiler should insert caching automatically, ideally with the aid of run-time profiling results. To support this, a new hook has been added:

Slot_t objc_msg_forward3(id receiver, SEL op);

This is identical to objc_msg_forward2(), but returns a pointer to a slot, instead of an IMP. The slot should have its version set to 0, to prevent caching.

Object Planes

Object planes provide interception points for messages between groups of related objects. They can be thought of as similar to processes, with mediated inter-plane communication. A typical use-case for an object plane is to automatically queue messages sent to a thread, or to record every message sent to model objects. Planes can dramatically reduce the number of proxy objects required for this kind of activity.

The GNUstep runtime adds a flag to class objects indicating that their instances are present in the global plane. All constant strings, protocols, and classes are in the global plane, and may therefore be sent and may receive messages bypassing the normal plane interception mechanism.

The runtime library does not provide direct support for planes, it merely provides the core components required to implement support for planes in another framework. Two objects are regarded as being in the same plane when they words immediately before their isa pointers are the same. In this case, the runtime's usual dispatch mechanisms will be used. In all other cases, the runtime will delegate message lookup to another library via the following hook:

Slot_t (*objc_plane_lookup)(id *receiver, SEL op, id sender);

From the perspective of the runtime, the plane identifier is opaque. In GNUstep, it is a pointer to an NSZone structure.

Threading

The threading APIs from GCC libobjc are not present in this runtime. They were buggy, badly supported, inadequately tested, and irrelevant now that there are well tested thread abstraction layers, such as the POSIX thread APIs and the C1x thread functions. The library always runs in thread-safe mode. The same functions for locking the runtime mutex are still supported, but their use any mutex not exported by the runtime library is explicitly not supported. The (private) lock.h header is used to abstract the details of different threading systems sufficiently for the runtime. This provides mechanisms for locking, unlocking, creating, and destroying mutex objects.

Type-Dependent Dispatch

Traditionally, Objective-C method lookup is done entirely on the name of the method. This is problematic when the sender and receiver of the method disagree on the types of a method.

For example, consider a trivial case where you have two methods with the same name, one taking an integer, the other taking a floating point value. Both will pass their argument in a register on most platforms, but not the same register. If the sender thinks it is calling one, but is really calling the other, then the receiver will look in the wrong register and use a nonsense value. The compiler will often not warn about this.

This is a relatively benign example, but if the mismatch is between methods taking or returning a structure and those only using scalar arguments and return then the call frame layout will be so different that the result will be stack corruption, possibly leading to security holes.

If you compile the GNUstep runtime with type-dependent dispatch enabled, then sending a message with a typed selector will only ever invoke a method with the same types. Sending a message with an untyped selector will invoke any method with a matching name, although the slot returned from the lookup function will contain the types, allowing the caller to check them and construct a valid call frame, if required.

If a lookup with a typed selector matches a method with the wrong types, the runtime will call a handler. This handler, by default, prints a helpful message and exits. LanguageKit provides an alternative version which dynamically generates a new method performing the required boxing and calling the original.

Exception ABI Changes

The non-fragile ABI makes a small change to the exception structure. The old GCC ABI was very poorly designed. It attempted to do things in a clever way, avoiding the need to call functions on entering and exiting catch blocks, but in doing so completely broke support for throwing foreign (e.g. C++) exceptions through Objective-C stack frames containing an @finally or @catch(id) block. It also could not differentiate between @catch(id) (catch any object type) and @catch(...) (catch any exception and discard it).

The new ABI makes a small number of changes. Most importantly, @catch(id) is now indicated by using the string "@id" as the type ID, in the same way that "Foo" is used for @catch(Foo*). Catchalls remain identified by a NULL pointer in this field, as with the GCC ABI. The runtime will still deliver the exception object to catchalls, for interoperability with old code and with the old ABI, but this comes with all of the same problems that the old ABI had (i.e. code using this ABI will break in exciting and spectacular ways when mixed with C++).

The runtime provides a hook, _objc_class_for_boxing_foreign_exception(), which takes an exception class (64-bit integer value) as an argument, and returns a class for boxing exceptions using this ABI. The returned class must implement a +exceptionWithForeignException: method, taking a pointer to the ABI-defined generic exception structure as the argument. It should also implement a -rethrow method, used for rethrowing the exception. If this is omitted, then the boxed version of the exception, rather than the original, will propagate out from @finally blocks.

If a catch block exists that handles this class, then it will box foreign exceptions and allow them to propagate through any @finally directives. Boxed exceptions will only match explicit catch statements. To fully understand the semantics, we'll take a look at some examples. These all use GNUstep's CXXException class, which boxes C++ exceptions, and this simple C++ function:

extern "C" void throwcxx()
{
	throw 1;
}

This exception will be caught, boxed, and then silently discarded by a catchall:

@try
{
	throwcxx();
}
@catch(...)
{
	// This will be reached, then the exception propagation stops.
}

If an id catch block is encountered, it will be ignored, but @finally blocks will still be called:

@try
{
	throwcxx();
}
@catch(id anyObject)
{
	// Code here is not reached.
}
@finally
{
	// This will be reached, then the exception propagation continues.
}

The CXXException class is a subclass of NSObject, but catch statements for the superclass will not be hit:

@try
{
	throwcxx();
}
@catch(NSObject *anyObject)
{
	// Code here is not reached.
}
@catch(CXXException *boxedForeign)
{
	// Code here is reached.
}

As of version 1.3, the runtime also provides a unified exception model for Objective-C++. This allows C++ catch statements and Objective-C @catch statements to catch Objective-C objects thrown with @throw or throw.

This required some small changes to the ABI. Both @try and try must use the same personality function in Objective-C++ code, because otherwise things like nested blocks are not possible. The unwind library must be able to map from any instruction pointer value to a single personality function, and without a unified personality function, it would not be able to in code like this:

@try
{
	try
	{
		// What personality function should be used when unwinding from
		// here?
		objc_exception_throw(@"foo");
	}
	catch (int i) {}
}
catch (id foo) {}

If there is a single personality function, there must be a single format for language-specific data. The current C++ format is more expressive than the Objective-C format, so we used it directly, with one extension. C++ landing pads are identified by a std::type_info subclass in the type info tables for exception unwinding. We provide two subclasses of this:

gnustep::libobjc::__objc_id_type_info;
gnustep::libobjc::__objc_class_type_info;

The first is used for identifying id-typed throws and catches. The second is for identifying Objective-C classes. All id throws use the singleton instance of the first class, exported as __objc_id_type_info (with C linkage). Type info for classes should generate an instance of the second class, with the name __objc_eh_typeinfo_Foo where Foo is the name of the class (e.g. NSObject should generate __objc_eh_typeinfo_NSObject). The name field should be set to the name of the class, via a global variable named __objc_eh_typename_Foo. Both should have link-once ODR linkage, so that the linker will ensure that they are unique and pointer comparison can be used to test for equality (required by the C++ personality function).

In Objective-C++ code, the personality function is:

__gnustep_objcxx_personality_v0()

This is a very thin wrapper around the C++ personality function. If it is called with an exception coming from Objective-C code, then it wraps it in a __cxa_exception structure (defined by the C++ ABI spec). For any other exception type (including C++ exceptions), it passes it directly to the C++ personality function.

The Objective-C personality function was also modified slightly so that any incoming C++ exception that was has type info indicating that it's an Objective-C type is treated as an Objective-C object, for the purpose of exception delivery.

Low Memory Profile

The dispatch tables for each class, in spite of using a more space-efficient sparse array implementation than GCC libobjc, can still use quite a lot of memory. The NeXT runtime avoided this problem by not providing dispatch tables at all. Instead, it did a linear search of the method lists, caching a few results. Although this is O(n), it performed reasonably well. Most message sends are to a small number of methods. For example, an NSMutableDictionary is most often sent -objectForKey: and -setObject:forKey:. If these two methods are in the cache, then the O(n) algorithm is almost never used.

The GNUstep runtime's low memory profile stores the slots in a sorted array. This means that the worst case performance is O(log(n)) in terms of the number of methods, as the uncached lookup proceeds using a binary search.

If you compile the GNUstep runtime with the low memory profile, it uses a similar strategy. The caches use the same slot-caching mechanism described above and can be combined with caching at the call site. The runtime will not create dispatch tables, which can save a few MB of RAM in projects with a lot of classes, but can make message sending a lot slower in the worst case.

To enable the low memory profile, add low_memory=yes to your make command line.

Objective-C 2 Features

The runtime now provides implementations of the functions required for the @synchronized directive, for property accessors, and for fast enumeration. The public runtime function interfaces now match those of OS X.

Garbage Collection

As of version 1.5, the runtime support Apple-compatible garbage collection semantics. The objc/objc-auto.h header describes the interfaces to garbage collection. This contains some extensions to Apple's API, required to implement parts of Cocoa that rely on private interfaces between Cocoa, Apple libobjc, and Autozone.

Garbage collection is implemented using the Boehm-Demers-Weiser garbage collector. If built with boehm_gc=no, this support will not be compiled into the runtime. When built with GC support, the runtime will use garbage collection for its internal tables, irrespective of whether linked Objective-C code is using it.

Zeroing weak references are implemented by storing the bit-flipped version of the value (making it invisible to the collector) at the designated address. The read barrier reads the value while holding the collector lock. This ensures that reads of weak variables never point to finalised objects.

The runtime uses the objc_assign_global() write barrier to add static roots. Currently, GNUstep crashes if the collector relies on every write of a pointer to a static location being through this write barrier, so this requirement is relaxed. It will be enabled at some point in the future.

Several environment variables can be used for debugging programs

  • LIBOBJC_DUMP_GC_STATUS_ON_EXIT. I this is set, then the program will dump information about the garbage collector when it exits.
  • LIBOBJC_DUMP_GC_STATUS_ON_SIGNAL. This should be set to a signal number. The program will dump GC statistics when it receives the corresponding signal (SIGUSR2 if this environment variable is set to something that is not a number).
  • LIBOBJC_LOG_ALLOCATIONS. This may be set to the name of a file. The runtime will dump a stack trace on every allocation and finalisation to the named file. This can be used to implement tools like Apple's malloc_history(). Note: Enabling this causes a significant speed decrease.
  • LIBOBJC_CANARIES. If this environment variable is set, then every allocation of garbage-collected memory will have a canary value appended to it. On finalisation, the runtime will check that this value has not been modified, and abort if it has. This can help to catch heap buffer overflows. It is most useful when debugging.

Automatic Reference Counting

As of version 1.5, the runtime provides support for automatic reference counting (ARC). This uses the same runtime interface as documented by the ABI supplement here:

http://clang.llvm.org/docs/AutomaticReferenceCounting.html#runtime

The runtime implements the following optimisations:

  • Classes that have ARC-compliant retain, release, and autorelease methods will never see them called from ARC code. Instead, equivalent code will be run directly.
  • If an object is autoreleased, returned, and retained, it is just stored in thread-local storage temporarily, not actually autoreleased.
  • Moving weak references skips the retain / release step.

ARC requires the ability to interoperate perfectly with manual retain / release code, including the ability for non-ARC code to implement custom reference counting behaviour. If an object implements -_ARCCompliantRetainRelease, then it is advertising that its -retain, -release, and -autorelease implementations are ARC-compatible. These methods may be called explicitly in non-ARC code, but will not be called from ARC.

ARC moves autorelease pools into the runtime. If NSAutoreleasePool exists and does not implement a -_ARCCompatibleAutoreleasePool method, then it will be used directly. If it does not exist, ARC will implement its own -autorelease pools. If it exists and does implement -_ARCCompatibleAutoreleasePool then it must call objc_autoreleasePoolPush() and objc_autoreleasePoolPop() to manage autoreleased object storage and call objc_autorelease() in its -addObject: method.