The fast paths follow the pattern that we established for fast ARC:
Framework base classes can opt in by implementing a `+_TrivialAllocInit`
method.
This opt-in behaviour is inherited and is removed implicitly in any
subclass that implements alloc or init methods (alloc and init are
treated independently).
Compilers can emit calls to `objc_alloc(cls)` instead of `[cls alloc]`,
`objc_allocWithZone(cls)` instead of `[cls allocWithZone: NULL]`, and
`objc_alloc_init` instead of `[[cls alloc] init]`.
Direct methods don't require very much support in the runtime. Apple
reuses their fast path for `-self` (which is supported only in the Apple
fork of clang, not the upstream version) for a fast init. Given that
the first few fields of the runtime's class structure have been stable
for around 30 years, I'm happy moving the flags word (and the
initialised bit, in particular) into the public ABI. This lets us do a
fast-path check for whether a class is initialised in class methods and
call `objc_send_initialize` if it isn't. This function is now exposed
as part of the public ABI, it was there already and does the relevant
checks without invoking any of the message-sending machinery.
Fixes#165#169
Reorders how locking is handled in `objc_send_initialize()` to prevent a deadlock.
Previously, contention on the low level spinlocks could cause a very intermittent deadlock:
- Thread A : `objc_send_initialize()` holds the runtime lock, then tries to acquire the object lock on the metaclass, which needs to initialize the mutex for the new metaclass inside `referenceListForObject()`, so it tries to lock the `lock_for_pointer()` / `lock_spinlock()`
- Thread B : `referenceListForObject()` holds a spinlock for an unrelated object while running `initHiddenClassForObject()` -> `allocateHiddenClass()`, which tries to acquire the runtime lock
If the metaclass object pointer in Thread A hashes to the same spinlock as the object in thread B, the runtime lock ends up deadlocked forever.
This cleans up handling of objects that are not reference counted and
makes their interactions with ARC more consistent. We should probably
generalise this somewhat - it currently special cases NSConstantString
and NSGlobalBlock, but it would be nice to have an API for constant
objects.
Several of the structures now end with an array of structures that may
have other fields added to them that the runtime doesn't know about yet
by a compiler. Rather than indexing into them directly, we must call an
accessor to find the correct address.
A few of the places where accesses were replaced were in functions where
it is safe because they only deal with versions of the structures that
are dynamically allocated (and will therefore have the correct size).
This was done to simplify future auditing: these fields should be
accessed directly only from the accessor functions in the header and
from the upgraders (currently in legacy.c).
Also fix a few bugs where the sizes weren't being filled in.
This change set incorporates a number of changes that all needed to
happen together:
* The imp is now the first field of the `objc_method` structure. This
makes it possible to extend the structure without breaking anything
that relies on being able to access the IMP.
* There is no owner in the slot, so we must use other mechanisms for
determining the owner of a method (e.g. whether the same method appears
in the superclass)
* Again, because there is no owner in the slot, we can't use this as a
fast path for finding the C++ construct / destruct methods. These are
now cached in the class structure when they are found.
* The version field is gone from the slot and now we provide a global
version. This is based on the observation that method replacements
are relatively infrequent and the overhead of invalidating all method
caches is cheaper than adding extra state for every (class, method)
pair.
* A number of the runtime functions are simplified because replacing
the IMP in a `Method` now implicitly updates the dtable.
at the start of the structure, making it easier to change the layout in
the future.
Also clean up the growth of various fields and consolidate some of the
metadata into a pointer to the `struct objc_method`.
This saves one load on the message send path for each tree depth (2
loads in the common case, 3 if you have a lot of selectors), which
should improve cache usage considerably.
Note: This is a checkpoint commit. Currently, every objc_msgSend()
implementation except for x86-64 is broken.
is meant to protect a runtime data structure while trying to acquire a lock
that must be held when running user code that may take an indeterminate amount
of time and may trigger deadlocks.
- Don't call C++ constructors if they don't exist.
- Don't check the owner of retain / release methods if they are not implemented.
- Add arc.m as a file to ignore when checking for GC compatibility.
- __strong pointers, preventing objects from being freed
_ __weak pointers are automatically freed when the last remaining __strong pointer goes away
- objc_gc_{retain,release}_np() functions, which can be used to implement CFRetain() and CFRelease() (adds an reference count - the object will not be collected until after its last retain is gone.