diff --git a/ANNOUNCE b/ANNOUNCE index 1d850db..b576487 100644 --- a/ANNOUNCE +++ b/ANNOUNCE @@ -24,7 +24,8 @@ in the 1980s. Highlights include: faster hashing and better unicode support. - Instance variable metadata includes size and alignment, allowing better object - layout and more accurate introspection. + layout and more accurate introspection. Instance variable metadata now + includes more accurate information about ARC ownership semantics. - Method metadata now includes extended type information, allowing bridged languages to understand the class that methods expect and not just the fact @@ -39,6 +40,12 @@ In addition to the new ABI, there are several improvements on Windows: - All of the assembly code paths now fully support i386 and x64 Windows. +- Object allocations on 32-bit Windows now use `_aligned_malloc` to guarantee + sufficient alignment for AVX vectors in instance variables. + +- The runtime now uses fibre-local storage and critical sections on Windows, + improving performance in multithreaded workloads on Windows. + - Public runtime functions are now marked dllexport, so the runtime can be built as objc.dll on Windows. diff --git a/README.md b/README.md index 196bf53..73df318 100644 --- a/README.md +++ b/README.md @@ -3,22 +3,27 @@ GNUstep Objective-C Runtime [![Build Status](https://travis-ci.org/gnustep/libobjc2.svg?branch=master)](https://travis-ci.org/gnustep/libobjc2) -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. +The GNUstep Objective-C runtime was designed as a drop-in replacement for the +GCC runtime. It supports three ABIs: + +- The old GCC ABI, which provides support for Objective-C 1.0 features. This + can be selected via the `-fobjc-runtime=gcc` flag in Clang or by compiling + with GCC. +- The initial GNUstep non-fragile ABI, which was intended to be compatible with + the GCC ABI, but provide support for modern Objective-C features. This can be + selected with the `-fobjc-runtime=gnustep-1.9` flag in Clang. +- The modern (v2) ABI, which provides richer reflection metadata, smaller + binaries and reduced memory usage. This is selected with the + `-fobjc-runtime=gnustep-2.0` flag in Clang 7.0 or later. + +The runtime can be built without support for older ABIs by setting the +`OLDABI_COMPAT` flag to `OFF` in CMake configuration. This will result in a +smaller binary, which will not link against code using the older ABIs. + +All ABIs support the following feature above and beyond the GCC runtime: + +- The modern Objective-C runtime APIs, initially 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 @@ -43,149 +48,8 @@ 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. +Various parts of Windows support were contributed by the WinObjC team at +Microsoft. Type-Dependent Dispatch ----------------------- @@ -219,252 +83,3 @@ 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. -