Skip to content
Snippets Groups Projects
Commit ea571b4f authored by Konstantin Osipov's avatar Konstantin Osipov
Browse files

Remove libobjc.

parent ad36622a
No related branches found
No related tags found
No related merge requests found
Showing
with 0 additions and 2333 deletions
#
# A macro to build the bundled libobjc
#
macro(libobjc_build)
if (${CMAKE_BUILD_TYPE} STREQUAL "Debug")
set (extra_cflags "${CC_DEBUG_OPT} -O0")
if (CMAKE_COMPILER_IS_GNUCC)
set (extra_cflags "${extra_cflags} -fno-inline")
endif()
set (extra_ldflags "")
else()
set (extra_cflags "-O3")
if (CC_HAS_WNO_UNUSED_RESULT)
set (extra_cflags "${extra_cflags} -Wno-unused-result")
endif()
set (extra_ldflags "-s")
endif()
if (TARGET_OS_LINUX)
set (extra_cflags "${extra_cflags} -D_GNU_SOURCE")
if (${CMAKE_SYSTEM_PROCESSOR} MATCHES "686")
set (extra_cflags "${extra_cflags} -march=i586")
endif()
endif()
if (CMAKE_COMPILER_IS_CLANG)
set (extra_cflags "${extra_cflags} -Wno-deprecated-objc-isa-usage")
set (extra_cflags "${extra_cflags} -Wno-objc-root-class")
endif()
set (extra_cflags "${extra_cflags} -Wno-attributes")
set (extra_cflags "${CMAKE_C_FLAGS} ${extra_cflags}")
if (HAVE_NON_C99_PTHREAD_H)
set (extra_cflags "${extra_cflags} -fgnu89-inline")
endif()
separate_arguments(extra_cflags)
separate_arguments(extra_ldflags)
if (NOT (${PROJECT_BINARY_DIR} STREQUAL ${PROJECT_SOURCE_DIR}))
add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/third_party/libobjc
COMMAND ${CMAKE_COMMAND} -E make_directory "${PROJECT_BINARY_DIR}/third_party/libobjc"
COMMAND cp -r ${PROJECT_SOURCE_DIR}/third_party/libobjc/*
${PROJECT_BINARY_DIR}/third_party/libobjc
)
endif()
add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/third_party/libobjc/libobjc.a
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/third_party/libobjc
COMMAND $(MAKE) clean
COMMAND $(MAKE) CC=${CMAKE_C_COMPILER} CXX=${CMAKE_CXX_COMPILER} EXTRA_CFLAGS="${extra_cflags}" EXTRA_LDFLAGS="${extra_ldflags}"
DEPENDS ${PROJECT_BINARY_DIR}/third_party/libobjc
${PROJECT_BINARY_DIR}/CMakeCache.txt
)
add_custom_target(objc ALL
DEPENDS ${PROJECT_BINARY_DIR}/third_party/libobjc/libobjc.a
)
set(LIBOBJC_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/third_party/libobjc)
set(LIBOBJC_LIBRARIES ${PROJECT_BINARY_DIR}/third_party/libobjc/libobjc.a)
message(STATUS "Use bundled libobjc includes: ${LIBOBJC_INCLUDE_DIR}")
message(STATUS "Use bundled libobjc library: ${LIBOBJC_LIBRARIES}")
unset (extra_cflags)
unset (extra_ldlags)
endmacro()
GNUstep Objective-C Runtime 1.7
===============================
This is a point release to the eighth official release of the GNUstep
Objective-C runtime (a.k.a. libobjc2). This runtime was designed to support
the features of modern dialects of Objective-C for use with GNUstep and other
Objective-C programs. Highlights of this release include:
- A new CMake-based build system. This makes all of the configurable options
available via a clean interface. CPack is supported for building RPM and DEB
packages out of the box.
- A new CTest-based test suite, replacing the old ad-hoc tests.
- Build a single libobjc with support for Objective-C++ on platforms where a
C++ ABI library (libcxxrt or libsupc++) is installed as a shared library.
- Added specialised property accessor functions and support for atomic
properties with C++ non-POD types.
- Significant improvements in property introspection and an exhaustive test
suite.
- A new exception implementation providing better integration with foreign
exceptions (e.g. C++ exceptions). The new ABI is supported by clang 3.3 when
compiling with -fobjc-runtime=gnustep-1.7 (or higher). The old ABI is still
supported and both can be used within the same program, however code compiled
with the old ABI remains unreliable in the presence of foreign exceptions.
It is strongly recommended that anyone using exceptions with Objective-C++
switches to the new version.
- MIPS64 support in the assembly routines. (TODO)
- Updated optimisation passes to work with LLVM 3.2 and recent LLVM trunk.
You may obtain the code for this release from subversion at the following
subversion branch:
svn://svn.gna.org/svn/gnustep/libs/libobjc2/1.7
Alternatively, a tarball is available from:
http://download.gna.org/gnustep/libobjc2-1.7.tar.bz2
The runtime library is responsible for implementing the core features of the
object model, as well as exposing introspection features to the user. The
GNUstep runtime implements Apple's Objective-C Runtime APIs, and a small number
of GCC APIs for legacy compatibility.
This library is based on the Étoilé Objective-C Runtime, an earlier research
prototype, and includes support for non-fragile instance variables,
type-dependent dispatch, and object planes. It is fully backwards compatible
with the FSF's GCC 4.2.1 Objective-C ABI and also implements a new ABI that is
supported by Clang and Étoilé's LanguageKit and is required for some of the
newer features.
If you come across any problems, please report them to the GNUstep Developer
mailing list <gnustep-dev@gnu.org>.
GNUstep Objective-C Runtime 1.0
===============================
This is the first official release of the GNUstep Objective-C runtime (a.k.a.
libobjc2). This runtime was designed to support the features of Objective-C 2
for use with GNUstep and other Objective-C programs.
You may obtain the code for this release from subversion at the following
subversion branch:
svn://svn.gna.org/svn/gnustep/libs/libobjc2/1.0
Alternatively, a tarball is available from:
http://download.gna.org/gnustep/libobjc2-1.0.tar.bz2
The runtime library is responsible for implementing the core features of the
object model, as well as exposing introspection features to the user. The
GNUstep runtime implements Apple's Objective-C Runtime APIs, and a small number
of GCC APIs for legacy compatibility.
This library is based on the Étoilé Objective-C Runtime, an earlier research
prototype, and includes support for non-fragile instance variables,
type-dependent dispatch, and object planes. It is fully compatible with the
FSF's GCC Objective-C ABI and also implements a new ABI that is supported by
Clang and is required for some of the newer features.
Although the runtime has been tested by several people, and is being used
extensively by the Étoilé project, it is entirely new (MIT licensed) code and
may still contain bugs. If you come across any problems, please report them to
the GNUstep Developer mailing list <gnustep-dev@gnu.org>. A 1.1 release,
fixing any bugs that are encountered in wider deployment, is planned to
coincide with the next GNUstep release.
GNUstep Objective-C Runtime 1.1
===============================
This is the second official release of the GNUstep Objective-C runtime (a.k.a.
libobjc2). This runtime was designed to support the features of Objective-C 2
for use with GNUstep and other Objective-C programs. This release contains
minor bug fixes and provides compatibility with synthesised declared properties
from GCC 4.6 and recent versions of clang.
You may obtain the code for this release from subversion at the following
subversion branch:
svn://svn.gna.org/svn/gnustep/libs/libobjc2/1.1
Alternatively, a tarball is available from:
http://download.gna.org/gnustep/libobjc2-1.1.tar.bz2
The runtime library is responsible for implementing the core features of the
object model, as well as exposing introspection features to the user. The
GNUstep runtime implements Apple's Objective-C Runtime APIs, and a small number
of GCC APIs for legacy compatibility.
This library is based on the Étoilé Objective-C Runtime, an earlier research
prototype, and includes support for non-fragile instance variables,
type-dependent dispatch, and object planes. It is fully compatible with the
FSF's GCC Objective-C ABI and also implements a new ABI that is supported by
Clang and is required for some of the newer features.
Although the runtime has been tested by several people, and is being used
extensively by the Étoilé project, it is entirely new (MIT licensed) code and
may still contain bugs. If you come across any problems, please report them to
the GNUstep Developer mailing list <gnustep-dev@gnu.org>.
GNUstep Objective-C Runtime 1.2
===============================
This is the 1.2 release of the GNUstep Objective-C runtime (a.k.a.
libobjc2). This runtime was designed to support the features of Objective-C 2
for use with GNUstep and other Objective-C programs. This release contains
several bug fixes, and is tested with the current GNUstep trunk, so will be
compatible with the upcoming GNUstep release.
You may obtain the code for this release from subversion at the following
subversion branch:
svn://svn.gna.org/svn/gnustep/libs/libobjc2/1.2
Alternatively, a tarball is available from:
http://download.gna.org/gnustep/libobjc2-1.2.tar.bz2
The runtime library is responsible for implementing the core features of the
object model, as well as exposing introspection features to the user. The
GNUstep runtime implements Apple's Objective-C Runtime APIs, and a small number
of GCC APIs for legacy compatibility.
This library is based on the Étoilé Objective-C Runtime, an earlier research
prototype, and includes support for non-fragile instance variables,
type-dependent dispatch, and object planes. It is fully compatible with the
FSF's GCC Objective-C ABI and also implements a new ABI that is supported by
Clang and is required for some of the newer features.
Although the runtime has been tested by several people, and is being used
extensively by the Étoilé project, it is entirely new (MIT licensed) code and
may still contain bugs. If you come across any problems, please report them to
the GNUstep Developer mailing list <gnustep-dev@gnu.org>.
GNUstep Objective-C Runtime 1.3
===============================
This is the fourth official release of the GNUstep Objective-C runtime (a.k.a.
libobjc2). This runtime was designed to support the features of Objective-C 2
for use with GNUstep and other Objective-C programs.
This release contains several bug fixes and includes a unified exception
model, providing the same features as Apple's Modern runtime for Objective-C++
code, specifically the ability to throw Objective-C objects with @throw() or
throw() and catch them with @catch() or catch(). The new unified exception
model is supported by Clang 2.9 and is compatible with Apple's Objective-C++
exception behaviour. Another enhancement in this release is the addition of
support for class aliases. This provides a run-time equivalent of
@compatibility_alias, allowing a class to show up in class lookup searching for
its alias.
You may obtain the code for this release from subversion at the following
subversion branch:
svn://svn.gna.org/svn/gnustep/libs/libobjc2/1.3
Alternatively, a tarball is available from:
http://download.gna.org/gnustep/libobjc2-1.3.tar.bz2
The runtime library is responsible for implementing the core features of the
object model, as well as exposing introspection features to the user. The
GNUstep runtime implements Apple's Objective-C Runtime APIs, and a small number
of GCC APIs for legacy compatibility.
This library is based on the Étoilé Objective-C Runtime, an earlier research
prototype, and includes support for non-fragile instance variables,
type-dependent dispatch, and object planes. It is fully compatible with the
FSF's GCC Objective-C ABI and also implements a new ABI that is supported by
Clang and Étoilé's LanguageKit and is required for some of the newer features.
Although the runtime has been tested by several people, and is being used
extensively by the Étoilé project, it is entirely new (MIT licensed) code and
may still contain bugs. If you come across any problems, please report them to
the GNUstep Developer mailing list <gnustep-dev@gnu.org>.
GNUstep Objective-C Runtime 1.4
===============================
This is the fifth official release of the GNUstep Objective-C runtime (a.k.a.
libobjc2). This runtime was designed to support the features of Objective-C 2
for use with GNUstep and other Objective-C programs. Highlights of this
release include:
- Support for the associated reference APIs introduced with OS X 10.6. This
allows storing arbitrary objects associated with another object.
- Concurrent, thread-safe, +initialize. The runtime will now send +initialize
messages to different classes concurrently in multiple threads, but still
ensures that no class receives another message until it has returned from
+initialize. This mirrors OS X behaviour. Care must be taken that
+initialize methods do not deadlock - if two classes are simultaneously
initialised from two different threads, and there +initialize methods call
methods in the other class, then deadlock will result.
- Exceptions can now safely propagate out of +initialize methods.
- Better hiding of local symbols. Now the internal runtime functions are not
visible from outside of the runtime. This may break code that attempts to
use private APIs, but means that it is now impossible to accidentally use
private APIs.
- Dispatch table updates have been improved. Category loading now longer
triggers dtable creation and partial dtable updates are faster.
- Improvements to the low memory profile. Uses 5-10% less (total) memory
running Gorm, and now passes the entire GNUstep and EtoileFoundation test
suites. Build with [g]make low_memory=yes to enable this mode. Note that
the low memory profile trades some CPU time for memory usage, so don't use it
for CPU-bound tasks.
- The class lookup cache optimisation (LLVM) now caches lookups irrespective of
the ABI. It will insert direct references to the class structures if
possible (i.e. if the symbol is visible). If not, then it will cache the
result of objc_class_lookup(). The cache is shared across the module (the
library, if run as a link-time optimisation), so the lookup only needs to be
run once. This eliminates the need for explicit class lookup caching in the
source code (when using LLVM-based compilers, such as Clang, LanguageKit, or
DragonEgg).
- Added some missing runtime API functions, such as those for setting and
getting instance variables. These are required by some language bridges,
although using them safely is not actually possible with the non-fragile ABI
(also true on OS X), since instance variables are no longer uniquely
identified by name.
- Added support for accessing property type encodings. These are extended type
encodings, allowing code introspecting the properties to learn if they are
read-only, their assignment policy, the methods used to implement them, and
so on.
You may obtain the code for this release from subversion at the following
subversion branch:
svn://svn.gna.org/svn/gnustep/libs/libobjc2/1.4
Alternatively, a tarball is available from:
http://download.gna.org/gnustep/libobjc2-1.4.tar.bz2
The runtime library is responsible for implementing the core features of the
object model, as well as exposing introspection features to the user. The
GNUstep runtime implements Apple's Objective-C Runtime APIs, and a small number
of GCC APIs for legacy compatibility.
This library is based on the Étoilé Objective-C Runtime, an earlier research
prototype, and includes support for non-fragile instance variables,
type-dependent dispatch, and object planes. It is fully compatible with the
FSF's GCC Objective-C ABI and also implements a new ABI that is supported by
Clang and Étoilé's LanguageKit and is required for some of the newer features.
Although the runtime has been tested by several people, and is being used
extensively by the Étoilé project, it is entirely new (MIT licensed) code and
may still contain bugs. If you come across any problems, please report them to
the GNUstep Developer mailing list <gnustep-dev@gnu.org>.
GNUstep Objective-C Runtime 1.5
===============================
This is the sixth official release of the GNUstep Objective-C runtime (a.k.a.
libobjc2). This runtime was designed to support the features of Objective-C 2
for use with GNUstep and other Objective-C programs. Highlights of this
release include:
- Support for Apple-compatible garbage collection APIs, along with extensions
to support CoreFoundation-style explicit reference counting in a garbage
collected environment. This uses the Boehm garbage collector and is enabled
by specifying boehm_gc=yes when building. This requires version 7.1 or later
of libgc. Code compiled with -fobjc-gc can be mixed with code that
implements normal reference counting and with code compiled with
-fobjc-gc-only. The runtime supports both GC and non-GC code when compiled
with GC support and will automatically select the correct behavior depending
on the loaded code.
- The runtime will now use Boehm GC for several internal data structures, if it
is built with GC enabled. This avoids the need for defensive programming
with respect to thread safety in several places.
- This is the first release to provide a superset of the functionality provided
by the Mac Objective-C runtime, as shipped with OS X 10.6.
- Full support for Automatic Reference Counting (ARC), compatible with OS X
10.7 and iOS 5, including support for __weak references.
- The LLVM optimisation passes have been improved and better tested. Code
compiled with them now passes the EtoileFoundation test suite.
You may obtain the code for this release from subversion at the following
subversion branch:
svn://svn.gna.org/svn/gnustep/libs/libobjc2/1.5
Alternatively, a tarball is available from:
http://download.gna.org/gnustep/libobjc2-1.5.tar.bz2
The runtime library is responsible for implementing the core features of the
object model, as well as exposing introspection features to the user. The
GNUstep runtime implements Apple's Objective-C Runtime APIs, and a small number
of GCC APIs for legacy compatibility.
This library is based on the Étoilé Objective-C Runtime, an earlier research
prototype, and includes support for non-fragile instance variables,
type-dependent dispatch, and object planes. It is fully compatible with the
FSF's GCC Objective-C ABI and also implements a new ABI that is supported by
Clang and Étoilé's LanguageKit and is required for some of the newer features.
Although the runtime has been tested by several people, and is being used
extensively by the Étoilé project, it is entirely new (MIT licensed) code and
may still contain bugs. If you come across any problems, please report them to
the GNUstep Developer mailing list <gnustep-dev@gnu.org>.
GNUstep Objective-C Runtime 1.6
===============================
This is the seventh official release of the GNUstep Objective-C runtime (a.k.a.
libobjc2). This runtime was designed to support the features of Objective-C 2
for use with GNUstep and other Objective-C programs. Highlights of this
release include:
- Compatibility with the new runtime APIs introduced with Mac OS X 10.7 / iOS 5.
- Support for small objects (ones hidden inside a pointer). On 32-bit systems,
the runtime permits one small object class, on 64-bit systems it permits 4.
This is used by GNUstep for small NSNumber and NSString instances, and these
are used by LanguageKit for message sending to small integers.
- Support for prototype-style object orientation. You can now add methods, as
well as associated references, to individual objects, and clone them. The
runtime now supports everything required for the JavaScript object model,
including the ability to use blocks as methods on x86, x86-64 and ARM.
- Support for Apple-compatible objc_msgSend() functions for x86, x86-64, and
ARM. Using these approximately halves the cost of message sending operations
and results in a 10% smaller total binary size.
- A fully maintained POSIX Makefile to make bootstrapping builds and packaging
easier. This will be used automatically if GNUstep Make is not installed.
- Improvements to the included LLVM optimisation passes. Testing on a 2.8GHz
Xeon, a loop of 200,000,000 class messages took 0.8 seconds with all
optimisations enabled (including speculative inlining). With -Os, the test
took 2 seconds. With explicit IMP caching in the source code, the test took
1.2 seconds. For reference, the same test using the GCC Objective-C runtime
took 11 seconds (when compiled with either Clang/LLVM or GCC).
Various features of this release required some per-platform assembly code. For
the 1.6.0 release, ARM, x86 and x86-64 (with the SysV ABI, not with the Win64
ABI) are supported. Future releases in the 1.6.x series will extend this to
other architectures.
You may obtain the code for this release from subversion at the following
subversion branch:
svn://svn.gna.org/svn/gnustep/libs/libobjc2/1.6
Alternatively, a tarball is available from:
http://download.gna.org/gnustep/libobjc2-1.6.tar.bz2
The runtime library is responsible for implementing the core features of the
object model, as well as exposing introspection features to the user. The
GNUstep runtime implements Apple's Objective-C Runtime APIs, and a small number
of GCC APIs for legacy compatibility.
This library is based on the Étoilé Objective-C Runtime, an earlier research
prototype, and includes support for non-fragile instance variables,
type-dependent dispatch, and object planes. It is fully backwards compatible
with the FSF's GCC 4.2.1 Objective-C ABI and also implements a new ABI that is
supported by Clang and Étoilé's LanguageKit and is required for some of the
newer features.
Although the runtime has been tested by several people, and is being used
extensively by the Étoilé project, it is relatively new code and may still
contain bugs. If you come across any problems, please report them to the
GNUstep Developer mailing list <gnustep-dev@gnu.org>.
GNUstep Objective-C Runtime 1.6.1
=================================
This is a point release to the seventh official release of the GNUstep
Objective-C runtime (a.k.a. libobjc2). This runtime was designed to support
the features of Objective-C 2 for use with GNUstep and other Objective-C
programs. Highlights of this release include:
- Improved support for ARC autorelease pools.
- Some small bug fixes in blocks support.
- Improvements to the Objective-C++ unified exception model support.
- Updated optimisation passes to work with LLVM 3.1
You may obtain the code for this release from subversion at the following
subversion branch:
svn://svn.gna.org/svn/gnustep/libs/libobjc2/1.6.1
Alternatively, a tarball is available from:
http://download.gna.org/gnustep/libobjc2-1.6.1.tar.bz2
The runtime library is responsible for implementing the core features of the
object model, as well as exposing introspection features to the user. The
GNUstep runtime implements Apple's Objective-C Runtime APIs, and a small number
of GCC APIs for legacy compatibility.
This library is based on the Étoilé Objective-C Runtime, an earlier research
prototype, and includes support for non-fragile instance variables,
type-dependent dispatch, and object planes. It is fully backwards compatible
with the FSF's GCC 4.2.1 Objective-C ABI and also implements a new ABI that is
supported by Clang and Étoilé's LanguageKit and is required for some of the
newer features.
Although the runtime has been tested by several people, and is being used
extensively by the Étoilé project, it is relatively new code and may still
contain bugs. If you come across any problems, please report them to the
GNUstep Developer mailing list <gnustep-dev@gnu.org>.
GNUstep Runtime APIs
====================
The GNUstep Objective-C runtime aims to implement all of the APIs defined in
Apple's Objective-C Runtime Reference. That document should be taken as the
authoritative reference to the majority of the APIs exposed by this runtime.
Any discrepancies between the implementations in this runtime and the
documentation should be regarded as a bug in the runtime.
In addition to these APIs, the runtime also exposes some non-portable APIs.
These are all marked as OBJC_NONPORTABLE in the headers. Many of these APIs
are also implemented in GNUstep's ObjectiveC2 framework, which uses the GCC
Objective-C runtime for the underlying implementation and provides a portable
set of APIs on top of the GCC runtime structures and functions.
Runtime Capabilities
--------------------
The objc/capabilities.h header defines runtime capabilities. A copy of this
header is also present in the ObjectiveC2 framework, so you can conditionally
include either version.
You can perform two sorts of checks using this header. Constants declared in
the header describe capabilities that the runtime may or may not implement. If
a capability is missing from this header, then it means that you are using an
old version of the runtime, which lacks any knowledge of the header. You can
use this to refuse to compile with old runtime versions.
You can also use the objc_test_capability() function to test whether a
particular capability is present at run time. Several of the capabilities are
optional in this runtime, and may not be compiled in to a given install. If
you require a particular capability, you can use the OBJC_REQUIRE_CAPABILITY()
macro to insert a load function that will abort if the capability is not present.
This shows how to refuse to compile or run with versions of the runtime that do
not support type-dependent dispatch:
#ifndef OBJC_CAP_TYPE_DEPENDENT_DISPATCH
# error Type-dependent dispatch support required!
#else
OBJC_REQUIRE_CAPABILITY(OBJC_CAP_TYPE_DEPENDENT_DISPATCH);
#endif
Typed Selectors
---------------
Like the GCC runtime, this runtime uses typed selectors. In recent versions,
message lookup is also dependent on the type of the selector by default. This
can be disabled by not defining the TYPE_DEPENDENT_DISPATCH macro when
building. When using GNU make, you can get name-dependent dispatch by doing:
$ gmake tdd=no
This is strongly discouraged. It will give compatibility with the semantics of
the NeXT, Apple, and GCC runtimes, however these semantics include random stack
corruption from valid code.
There are three functions for dealing with typed selectors. The first two are
direct equivalents of other functions.
SEL sel_registerTypedName_np(const char *selName, const char *types);
sel_registerName() will register an untyped selector. This variant registers a
typed selector, using the specified name and type encoding.
const char *sel_getType_np(SEL aSel);
This function simply returns the type encoding of the given selector, or NULL for a typed selector.
unsigned sel_copyTypes_np(const char *selName,
const char **types,
unsigned count);
This function copies *all* of the type encodings for a given selector name.
Generally, there are not many of these. In a well-written program, there will
be exactly one type encoding for a given selector. In a typical program, there
will be 1-3. It is not worth allocating a buffer on the heap for most cases,
so this function is designed to take a stack buffer.
Unlike other functions in the runtime, this always returns the total number of
type encodings, not the number that were found. This means that you can call
it once with a smallish on-stack buffer and then call it again with a
malloc()'d buffer if there are a lot of encodings for a specific selector, as
follows.
char *t[16];
char *types = t;
unsigned total = sel_copyTypes_np("alloc", types, total);
if (total > 16)
{
types = calloc(sizeof(char*), total);
sel_copyTypes_np("alloc", types, total);
}
// Do stuff with the types.
if (total > 16)
{
free(types);
}
**Note**: This runtime does not provide any equivalent of the GCC runtime's
sel_get_typed_uid() or sel_get_any_typed_uid(). This is intentional. It is
impossible to use these functions correctly and they should never have been
made part of the public API.
Message Sending
---------------
For ABI compatibility with the GCC runtime, this runtime implements the
objc_msg_lookup() and objc_msg_lookup_super() functions used to implement
message sending.
The new ABI uses the objc_msg_lookup_sender() function in place of
objc_msg_lookup(). This allows fast proxies and caching of the lookup result
at the callsite. You can find more a detailed explanation of how this works in
the README file.
This runtime also provides this semi-private function, which can be of use in
implementing parts of the Foundation framework and similar low-level libraries:
struct objc_slot* objc_get_slot(Class cls, SEL selector);
This looks up the slot for a given selector, without invoking any forwarding
mechanisms. This is most useful for quickly finding the type encoding of a
method (e.g. for implementing forwarding). The lookup is as fast as a normal
message lookup, and the types field of the returned slot provides the type
encoding. This is significantly faster than using class_getInstanceMethod(),
which needs to perform a linear search along a list (O(1) vs O(n)).
Hooks
-----
All of the callback hooks provided by this runtime are described in
objc/hooks.h.
Copyright (c) 2009 David Chisnall
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
.POSIX:
.SUFFIXES: .cc .c .m .o .S
MAJOR_VERSION = 4
MINOR_VERSION = 6
SUBMINOR_VERSION = 0
VERSION ?= $(MAJOR_VERSION).$(MINOR_VERSION).$(SUBMINOR_VERSION)
LIBOBJCLIBNAME=objc
LIBOBJC=libobjc
LIBOBJCXX=libobjcxx
INSTALL ?= install
#SILENT ?= @
CFLAGS += -std=gnu99 -fexceptions
#CFLAGS += -Wno-deprecated-objc-isa-usage
CXXFLAGS += -fexceptions
CPPFLAGS += -DTYPE_DEPENDENT_DISPATCH -DGNUSTEP
CPPFLAGS += -D__OBJC_RUNTIME_INTERNAL__=1 -D_XOPEN_SOURCE=500 -D__BSD_VISIBLE=1 -D_BSD_SOURCE=1
ASMFLAGS += `if $(CC) -v 2>&1| grep -q 'clang' ; then echo -no-integrated-as ; fi`
THE_LD=`if [ "$(LD)" = "" ]; then echo "ld"; else echo "$(LD)"; fi`
STRIP=`if [ "$(strip)" = "yes" ] ; then echo -s ; fi`
# Suppress warnings about incorrect selectors
CPPFLAGS += -DNO_SELECTOR_MISMATCH_WARNINGS
# Some helpful flags for debugging.
CPPFLAGS+= ${EXTRA_CFLAGS}
##CPPFLAGS += -g -O0 -fno-inline
#CPPFLAGS += -O3
PREFIX?= /usr/local
LIB_DIR= ${PREFIX}/lib
HEADER_DIR= ${PREFIX}/include
OBJCXX_OBJECTS = \
objcxx_eh.o
OBJECTS = \
NSBlocks.o\
Protocol2.o\
abi_version.o\
alias_table.o\
arc.o\
associate.o\
blocks_runtime.o\
block_to_imp.o\
block_trampolines.o\
objc_msgSend.o\
caps.o\
category_loader.o\
class_table.o\
dtable.o\
eh_personality.o\
encoding2.o\
gc_none.o\
hash_table.o\
hooks.o\
ivar.o\
legacy_malloc.o\
loader.o\
mutation.o\
properties.o\
protocol.o\
runtime.o\
sarray2.o\
selector_table.o\
sendmsg2.o\
statics_loader.o\
toydispatch.o
all: $(LIBOBJC).a
$(LIBOBJCXX).so.$(VERSION): $(LIBOBJC).so.$(VERSION) $(OBJCXX_OBJECTS)
$(SILENT)echo Linking shared Objective-C++ runtime library...
$(SILENT)$(CXX) -shared \
-Wl,-soname=$(LIBOBJCXX).so.$(MAJOR_VERSION) $(LDFLAGS) \
-o $@ $(OBJCXX_OBJECTS)
$(LIBOBJC).so.$(VERSION): $(OBJECTS)
$(SILENT)echo Linking shared Objective-C runtime library...
$(SILENT)$(CC) -shared -rdynamic \
-Wl,-soname=$(LIBOBJC).so.$(MAJOR_VERSION) $(LDFLAGS) \
-o $@ $(OBJECTS)
$(LIBOBJC).a: $(OBJECTS)
$(SILENT)echo Linking static Objective-C runtime library...
$(SILENT)$(THE_LD) -r -s -o $@ $(OBJECTS)
.cc.o: Makefile
$(SILENT)echo Compiling `basename $<`...
$(SILENT)$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
.c.o: Makefile
$(SILENT)echo Compiling `basename $<`...
$(SILENT)$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
.m.o: Makefile
$(SILENT)echo Compiling `basename $<`...
$(SILENT)$(CC) $(CPPFLAGS) $(CFLAGS) -fobjc-exceptions -c $< -o $@
.S.o: Makefile
$(SILENT)echo Assembling `basename $<`...
$(SILENT)$(CC) $(CPPFLAGS) $(ASMFLAGS) -c $< -o $@
$(INSTALL): all
$(SILENT)echo Installing libraries...
$(SILENT)install -d $(LIB_DIR)
$(SILENT)install -m 444 $(STRIP) $(LIBOBJC).so.$(VERSION) $(LIB_DIR)
$(SILENT)install -m 444 $(STRIP) $(LIBOBJCXX).so.$(VERSION) $(LIB_DIR)
$(SILENT)install -m 444 $(STRIP) $(LIBOBJC).a $(LIB_DIR)
$(SILENT)echo Creating symbolic links...
$(SILENT)ln -sf $(LIBOBJC).so.$(VERSION) $(LIB_DIR)/$(LIBOBJC).so
$(SILENT)ln -sf $(LIBOBJC).so.$(VERSION) $(LIB_DIR)/$(LIBOBJC).so.$(MAJOR_VERSION)
$(SILENT)ln -sf $(LIBOBJC).so.$(VERSION) $(LIB_DIR)/$(LIBOBJC).so.$(MAJOR_VERSION).$(MINOR_VERSION)
$(SILENT)ln -sf $(LIBOBJCXX).so.$(VERSION) $(LIB_DIR)/$(LIBOBJCXX).so
$(SILENT)ln -sf $(LIBOBJCXX).so.$(VERSION) $(LIB_DIR)/$(LIBOBJCXX).so.$(MAJOR_VERSION)
$(SILENT)ln -sf $(LIBOBJCXX).so.$(VERSION) $(LIB_DIR)/$(LIBOBJCXX).so.$(MAJOR_VERSION).$(MINOR_VERSION)
$(SILENT)echo Installing headers...
$(SILENT)install -d $(HEADER_DIR)/objc
$(SILENT)install -m 444 objc/*.h $(HEADER_DIR)/objc
clean:
$(SILENT)echo Cleaning...
$(SILENT)rm -f $(OBJECTS)
$(SILENT)rm -f $(OBJCXX_OBJECTS)
$(SILENT)rm -f $(LIBOBJC).so.$(VERSION)
$(SILENT)rm -f $(LIBOBJCXX).so.$(VERSION)
$(SILENT)rm -f $(LIBOBJC).a
#import "objc/runtime.h"
#import "class.h"
#import "lock.h"
#import "objc/blocks_runtime.h"
#import "dtable.h"
#include <assert.h>
struct objc_class _NSConcreteGlobalBlock;
struct objc_class _NSConcreteStackBlock;
struct objc_class _NSConcreteMallocBlock;
static struct objc_class _NSConcreteGlobalBlockMeta;
static struct objc_class _NSConcreteStackBlockMeta;
static struct objc_class _NSConcreteMallocBlockMeta;
static struct objc_class _NSBlock;
static struct objc_class _NSBlockMeta;
static void createNSBlockSubclass(Class superclass, Class newClass,
Class metaClass, char *name)
{
// Initialize the metaclass
//metaClass->class_pointer = superclass->class_pointer;
//metaClass->super_class = superclass->class_pointer;
metaClass->info = objc_class_flag_meta;
metaClass->dtable = uninstalled_dtable;
// Set up the new class
newClass->isa = metaClass;
newClass->super_class = (Class)superclass->name;
newClass->name = name;
newClass->info = objc_class_flag_class;
newClass->dtable = uninstalled_dtable;
LOCK_RUNTIME_FOR_SCOPE();
class_table_insert(newClass);
}
#define NEW_CLASS(super, sub) \
createNSBlockSubclass(super, &sub, &sub ## Meta, #sub)
BOOL objc_create_block_classes_as_subclasses_of(Class super)
{
if (_NSBlock.super_class != NULL) { return NO; }
NEW_CLASS(super, _NSBlock);
NEW_CLASS(&_NSBlock, _NSConcreteStackBlock);
NEW_CLASS(&_NSBlock, _NSConcreteGlobalBlock);
NEW_CLASS(&_NSBlock, _NSConcreteMallocBlock);
return YES;
}
#include "objc/runtime.h"
#include "protocol.h"
#include "class.h"
#include <stdio.h>
#include <string.h>
@implementation Protocol
// FIXME: This needs removing, but it's included for now because GNUstep's
// implementation of +[NSObject conformsToProtocol:] calls it.
- (BOOL)conformsTo: (Protocol*)p
{
return protocol_conformsToProtocol(self, p);
}
- (id)retain
{
return self;
}
- (void)release {}
+ (Class)class { return self; }
- (id)self { return self; }
@end
@implementation Protocol2 @end
/**
* This class exists for the sole reason that the legacy GNU ABI did not
* provide a way of registering protocols with the runtime. With the new ABI,
* every protocol in a compilation unit that is not referenced should be added
* in a category on this class. This ensures that the runtime sees every
* protocol at least once and can perform uniquing.
*/
@interface __ObjC_Protocol_Holder_Ugly_Hack { id isa; } @end
@implementation __ObjC_Protocol_Holder_Ugly_Hack @end
@implementation Object @end
This diff is collapsed.
#include "visibility.h"
#include "objc/runtime.h"
#include "module.h"
#include "gc_ops.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
/**
* The smallest ABI version number of loaded modules.
*/
static unsigned long min_loaded_version;
/**
* The largest ABI version number of loaded modules.
*/
static unsigned long max_loaded_version;
/**
* Structure defining the compatibility between Objective-C ABI versions.
*/
struct objc_abi_version
{
/** Version of this ABI. */
unsigned long version;
/** Lowest ABI version that this is compatible with. */
unsigned long min_compatible_version;
/** Highest ABI version compatible with this. */
unsigned long max_compatible_version;
/** Size of the module structure for this ABI version. */
unsigned long module_size;
};
enum
{
gcc_abi = 8,
gnustep_abi = 9,
gc_abi = 10
};
/**
* List of supported ABIs.
*/
static struct objc_abi_version known_abis[] =
{
/* GCC ABI. */
{gcc_abi, gcc_abi, gnustep_abi, sizeof(struct objc_module_abi_8)},
/* Non-fragile ABI. */
{gnustep_abi, gcc_abi, gc_abi, sizeof(struct objc_module_abi_8)},
/* GC ABI. Adds a field describing the GC mode. */
{gc_abi, gcc_abi, gc_abi, sizeof(struct objc_module_abi_10)}
};
static int known_abi_count =
(sizeof(known_abis) / sizeof(struct objc_abi_version));
#define FAIL_IF(x, msg) do {\
if (x)\
{\
fprintf(stderr, "Objective-C ABI Error: %s while loading %s\n", msg, module->name);\
return NO;\
}\
} while(0)
PRIVATE enum objc_gc_mode current_gc_mode = GC_Optional;
static BOOL endsWith(const char *string, const char *suffix)
{
if (NULL == string) { return NO; }
char *interior = strstr(string, suffix);
return (interior && (strlen(suffix) == strlen(interior)));
}
PRIVATE BOOL objc_check_abi_version(struct objc_module_abi_8 *module)
{
static int runtime_modules = 5;
// As a quick and ugly hack, skip these three tests for the .m files in the
// runtime. They should (in theory, at least) be aware of the GC mode and
// behave accordingly.
if (runtime_modules > 0)
{
if (endsWith(module->name, "properties.m") ||
endsWith(module->name, "associate.m") ||
endsWith(module->name, "arc.m") ||
endsWith(module->name, "blocks_runtime.m") ||
endsWith(module->name, "Protocol2.m"))
{
runtime_modules--;
return YES;
}
}
unsigned long version = module->version;
unsigned long module_size = module->size;
enum objc_gc_mode gc_mode = (version < gc_abi) ? GC_None
: ((struct objc_module_abi_10*)module)->gc_mode;
struct objc_abi_version *v = NULL;
for (int i=0 ; i<known_abi_count ; i++)
{
if (known_abis[i].version == version)
{
v = &known_abis[i];
break;
}
}
FAIL_IF(NULL == v, "Unknown ABI version");
FAIL_IF((v->module_size != module_size), "Incorrect module size");
// Only check for ABI compatibility if
if (min_loaded_version > 0)
{
FAIL_IF((v->min_compatible_version > min_loaded_version),
"Loading modules from incompatible ABIs");
FAIL_IF((v->max_compatible_version < max_loaded_version),
"Loading modules from incompatible ABIs");
if (min_loaded_version > version)
{
min_loaded_version = version;
}
if (max_loaded_version < version)
{
max_loaded_version = version;
}
}
else
{
min_loaded_version = version;
max_loaded_version = version;
}
// If we're currently in GC-optional mode, then fall to one side or the
// other if this module requires / doesn't support GC
if (current_gc_mode == GC_Optional)
{
current_gc_mode = gc_mode;
if (gc_mode == GC_Required)
{
enableGC(NO);
}
}
// We can't mix GC_None and GC_Required code, but we can mix any other
// combination
FAIL_IF((gc_mode == GC_Required) && (gc_mode != current_gc_mode),
"Attempting to mix GC and non-GC code!");
return YES;
}
/** Declaration of a helper function for getting class references from aliases.
Copyright (c) 2011 Free Software Foundation, Inc.
Written by: Niels Grewe <niels.grewe@halbordnung.de>
Created: March 2011
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "objc/runtime.h"
Class alias_getClass(const char *alias_name);
/** A hash table for mapping compatibility aliases to classes.
Copyright (c) 2011 Free Software Foundation, Inc.
Written by: Niels Grewe <niels.grewe@halbordnung.de>
Created: March 2011
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "visibility.h"
#include "objc/runtime.h"
#include "class.h"
#include "lock.h"
#include "string_hash.h"
#include <stdlib.h>
struct objc_alias
{
const char* name;
Class class;
};
typedef struct objc_alias Alias;
static int alias_compare(const char *name, const Alias alias)
{
return string_compare(name, alias.name);
}
static int alias_hash(const Alias alias)
{
return string_hash(alias.name);
}
static int alias_is_null(const Alias alias)
{
return alias.name == NULL;
}
static Alias NullAlias;
#define MAP_TABLE_NAME alias_table_internal
#define MAP_TABLE_COMPARE_FUNCTION alias_compare
#define MAP_TABLE_HASH_KEY string_hash
#define MAP_TABLE_HASH_VALUE alias_hash
#define MAP_TABLE_VALUE_TYPE struct objc_alias
#define MAP_TABLE_VALUE_NULL alias_is_null
#define MAP_TABLE_VALUE_PLACEHOLDER NullAlias
#include "hash_table.h"
static alias_table_internal_table *alias_table;
PRIVATE void init_alias_table(void)
{
alias_table_internal_initialize(&alias_table, 128);
}
static Alias alias_table_get_safe(const char *alias_name)
{
return alias_table_internal_table_get(alias_table, alias_name);
}
Class alias_getClass(const char *alias_name)
{
if (NULL == alias_name)
{
return NULL;
}
Alias alias = alias_table_get_safe(alias_name);
if (NULL == alias.name)
{
return NULL;
}
return alias.class;
}
PRIVATE void alias_table_insert(Alias alias)
{
alias_table_internal_insert(alias_table, alias);
}
BOOL class_registerAlias_np(Class class, const char *alias)
{
if ((NULL == alias) || (NULL == class))
{
return 0;
}
/*
* If there already exists a matching alias, determine whether we the existing
* alias is the correct one. Please note that objc_getClass() goes through the
* alias lookup and will create the alias table if necessary.
*/
Class existingClass = (Class)objc_getClass(alias);
if (NULL != existingClass)
{
/*
* Return YES if the alias has already been registered for this very
* class, and NO if the alias is already used for another class.
*/
return (class == existingClass);
}
Alias newAlias = { strdup(alias), class };
alias_table_insert(newAlias);
return 1;
}
#include <stdlib.h>
#include <assert.h>
#import "stdio.h"
#import "objc/runtime.h"
#import "objc/blocks_runtime.h"
#import "nsobject.h"
#import "class.h"
#import "selector.h"
#import "visibility.h"
#import "objc/hooks.h"
#import "objc/objc-arc.h"
#import "objc/blocks_runtime.h"
#ifndef NO_PTHREADS
#include <pthread.h>
pthread_key_t ARCThreadKey;
#endif
extern char _NSConcreteMallocBlock;
extern char _NSConcreteStackBlock;
extern char _NSConcreteGlobalBlock;
@interface NSAutoreleasePool
+ (Class)class;
+ (id)new;
- (void)release;
@end
#define POOL_SIZE (4096 / sizeof(void*) - (2 * sizeof(void*)))
/**
* Structure used for ARC-managed autorelease pools. This structure should be
* exactly one page in size, so that it can be quickly allocated. This does
* not correspond directly to an autorelease pool. The 'pool' returned by
* objc_autoreleasePoolPush() may be an interior pointer to one of these
* structures.
*/
struct arc_autorelease_pool
{
/**
* Pointer to the previous autorelease pool structure in the chain. Set
* when pushing a new structure on the stack, popped during cleanup.
*/
struct arc_autorelease_pool *previous;
/**
* The current insert point.
*/
id *insert;
/**
* The remainder of the page, an array of object pointers.
*/
id pool[POOL_SIZE];
};
struct arc_tls
{
struct arc_autorelease_pool *pool;
id returnRetained;
};
static inline struct arc_tls* getARCThreadData(void)
{
#ifdef NO_PTHREADS
return NULL;
#else
struct arc_tls *tls = pthread_getspecific(ARCThreadKey);
if (NULL == tls)
{
tls = calloc(sizeof(struct arc_tls), 1);
pthread_setspecific(ARCThreadKey, tls);
}
return tls;
#endif
}
int count = 0;
int poolCount = 0;
static inline void release(id obj);
/**
* Empties objects from the autorelease pool, stating at the head of the list
* specified by pool and continuing until it reaches the stop point. If the stop point is NULL then
*/
static void emptyPool(struct arc_tls *tls, id *stop)
{
struct arc_autorelease_pool *stopPool = NULL;
if (NULL != stop)
{
stopPool = tls->pool;
while (1)
{
// Invalid stop location
if (NULL == stopPool)
{
return;
}
// NULL is the placeholder for the top-level pool
if (NULL == stop && stopPool->previous == NULL)
{
break;
}
// Stop location was found in this pool
if ((stop >= stopPool->pool) && (stop < &stopPool->pool[POOL_SIZE]))
{
break;
}
stopPool = stopPool->previous;
}
}
while (tls->pool != stopPool)
{
while (tls->pool->insert > tls->pool->pool)
{
tls->pool->insert--;
// This may autorelease some other objects, so we have to work in
// the case where the autorelease pool is extended during a -release.
release(*tls->pool->insert);
count--;
}
void *old = tls->pool;
tls->pool = tls->pool->previous;
free(old);
}
if (NULL != tls->pool)
{
while ((stop == NULL || (tls->pool->insert > stop)) &&
(tls->pool->insert > tls->pool->pool))
{
tls->pool->insert--;
count--;
release(*tls->pool->insert);
}
}
//fprintf(stderr, "New insert: %p. Stop: %p\n", tls->pool->insert, stop);
}
static void cleanupPools(struct arc_tls* tls)
{
if (tls->returnRetained)
{
release(tls->returnRetained);
tls->returnRetained = nil;
}
if (NULL != tls->pool)
{
emptyPool(tls, NULL);
assert(NULL == tls->pool);
}
if (tls->returnRetained)
{
cleanupPools(tls);
}
free(tls);
}
static Class AutoreleasePool;
static IMP NewAutoreleasePool;
static IMP DeleteAutoreleasePool;
static IMP AutoreleaseAdd;
extern BOOL FastARCRetain;
extern BOOL FastARCRelease;
extern BOOL FastARCAutorelease;
static BOOL useARCAutoreleasePool;
static inline id retain(id obj)
{
if (isSmallObject(obj)) { return obj; }
Class cls = obj->isa;
if ((Class)&_NSConcreteMallocBlock == cls ||
(Class)&_NSConcreteStackBlock == cls)
{
return Block_copy(obj);
}
if (objc_test_class_flag(cls, objc_class_flag_fast_arc))
{
intptr_t *refCount = ((intptr_t*)obj) - 1;
__sync_add_and_fetch(refCount, 1);
return obj;
}
return [obj retain];
}
static inline void release(id obj)
{
if (isSmallObject(obj)) { return; }
Class cls = obj->isa;
if (cls == (Class)&_NSConcreteMallocBlock)
{
_Block_release(obj);
return;
}
if ((cls == (Class)&_NSConcreteStackBlock) ||
(cls == (Class)&_NSConcreteGlobalBlock))
{
return;
}
if (objc_test_class_flag(cls, objc_class_flag_fast_arc))
{
intptr_t *refCount = ((intptr_t*)obj) - 1;
if (__sync_sub_and_fetch(refCount, 1) < 0)
{
objc_delete_weak_refs(obj);
[obj dealloc];
}
return;
}
[obj release];
}
static inline void initAutorelease(void)
{
if (Nil == AutoreleasePool)
{
AutoreleasePool = objc_getRequiredClass("NSAutoreleasePool");
if (Nil == AutoreleasePool)
{
useARCAutoreleasePool = YES;
}
else
{
[AutoreleasePool class];
useARCAutoreleasePool = class_respondsToSelector(AutoreleasePool,
SELECTOR(_ARCCompatibleAutoreleasePool));
NewAutoreleasePool = class_getMethodImplementation(object_getClass(AutoreleasePool),
SELECTOR(new));
DeleteAutoreleasePool = class_getMethodImplementation(AutoreleasePool,
SELECTOR(release));
AutoreleaseAdd = class_getMethodImplementation(object_getClass(AutoreleasePool),
SELECTOR(addObject:));
}
}
}
static inline id autorelease(id obj)
{
//fprintf(stderr, "Autoreleasing %p\n", obj);
if (useARCAutoreleasePool)
{
struct arc_tls *tls = getARCThreadData();
if (NULL != tls)
{
struct arc_autorelease_pool *pool = tls->pool;
if (NULL == pool || (pool->insert >= &pool->pool[POOL_SIZE]))
{
pool = calloc(sizeof(struct arc_autorelease_pool), 1);
pool->previous = tls->pool;
pool->insert = pool->pool;
tls->pool = pool;
}
count++;
*pool->insert = obj;
pool->insert++;
return obj;
}
}
if (objc_test_class_flag(classForObject(obj), objc_class_flag_fast_arc))
{
initAutorelease();
if (0 != AutoreleaseAdd)
{
AutoreleaseAdd(AutoreleasePool, SELECTOR(addObject:), obj);
}
return obj;
}
return [obj autorelease];
}
unsigned long objc_arc_autorelease_count_np(void)
{
struct arc_tls* tls = getARCThreadData();
unsigned long count = 0;
if (!tls) { return 0; }
for (struct arc_autorelease_pool *pool=tls->pool ;
NULL != pool ;
pool = pool->previous)
{
count += (((intptr_t)pool->insert) - ((intptr_t)pool->pool)) / sizeof(id);
}
return count;
}
unsigned long objc_arc_autorelease_count_for_object_np(id obj)
{
struct arc_tls* tls = getARCThreadData();
unsigned long count = 0;
if (!tls) { return 0; }
for (struct arc_autorelease_pool *pool=tls->pool ;
NULL != pool ;
pool = pool->previous)
{
for (id* o = pool->insert-1 ; o >= pool->pool ; o--)
{
if (*o == obj)
{
count++;
}
}
}
return count;
}
void *objc_autoreleasePoolPush(void)
{
initAutorelease();
struct arc_tls* tls = getARCThreadData();
// If there is an object in the return-retained slot, then we need to
// promote it to the real autorelease pool BEFORE pushing the new
// autorelease pool. If we don't, then it may be prematurely autoreleased.
if ((NULL != tls) && (nil != tls->returnRetained))
{
autorelease(tls->returnRetained);
tls->returnRetained = nil;
}
if (useARCAutoreleasePool)
{
if (NULL != tls)
{
struct arc_autorelease_pool *pool = tls->pool;
if (NULL == pool || (pool->insert >= &pool->pool[POOL_SIZE]))
{
pool = calloc(sizeof(struct arc_autorelease_pool), 1);
pool->previous = tls->pool;
pool->insert = pool->pool;
tls->pool = pool;
}
// If there is no autorelease pool allocated for this thread, then
// we lazily allocate one the first time something is autoreleased.
return (NULL != tls->pool) ? tls->pool->insert : NULL;
}
}
initAutorelease();
if (0 == NewAutoreleasePool) { return NULL; }
return NewAutoreleasePool(AutoreleasePool, SELECTOR(new));
}
void objc_autoreleasePoolPop(void *pool)
{
if (useARCAutoreleasePool)
{
struct arc_tls* tls = getARCThreadData();
if (NULL != tls)
{
if (NULL != tls->pool)
{
emptyPool(tls, pool);
}
return;
}
}
DeleteAutoreleasePool(pool, SELECTOR(release));
struct arc_tls* tls = getARCThreadData();
if (tls && tls->returnRetained)
{
release(tls->returnRetained);
tls->returnRetained = nil;
}
}
id objc_autorelease(id obj)
{
if (nil != obj)
{
obj = autorelease(obj);
}
return obj;
}
id objc_autoreleaseReturnValue(id obj)
{
if (!useARCAutoreleasePool)
{
struct arc_tls* tls = getARCThreadData();
if (NULL != tls)
{
objc_autorelease(tls->returnRetained);
tls->returnRetained = obj;
return obj;
}
}
return objc_autorelease(obj);
}
id objc_retainAutoreleasedReturnValue(id obj)
{
// If the previous object was released with objc_autoreleaseReturnValue()
// just before return, then it will not have actually been autoreleased.
// Instead, it will have been stored in TLS. We just remove it from TLS
// and undo the fake autorelease.
//
// If the object was not returned with objc_autoreleaseReturnValue() then
// we actually autorelease the fake object. and then retain the argument.
// In tis case, this is equivalent to objc_retain().
struct arc_tls* tls = getARCThreadData();
if (NULL != tls)
{
// If we're using our own autorelease pool, just pop the object from the top
if (useARCAutoreleasePool)
{
if ((NULL != tls->pool) &&
(*(tls->pool->insert-1) == obj))
{
tls->pool->insert--;
return obj;
}
}
else if (obj == tls->returnRetained)
{
tls->returnRetained = NULL;
return obj;
}
}
return objc_retain(obj);
}
id objc_retain(id obj)
{
if (nil == obj) { return nil; }
return retain(obj);
}
id objc_retainAutorelease(id obj)
{
return objc_autorelease(objc_retain(obj));
}
id objc_retainAutoreleaseReturnValue(id obj)
{
if (nil == obj) { return obj; }
return objc_autoreleaseReturnValue(retain(obj));
}
id objc_retainBlock(id b)
{
return _Block_copy(b);
}
void objc_release(id obj)
{
if (nil == obj) { return; }
release(obj);
}
id objc_storeStrong(id *addr, id value)
{
value = objc_retain(value);
id oldValue = *addr;
*addr = value;
objc_release(oldValue);
return value;
}
////////////////////////////////////////////////////////////////////////////////
// Weak references
////////////////////////////////////////////////////////////////////////////////
typedef struct objc_weak_ref
{
id obj;
id *ref[4];
struct objc_weak_ref *next;
} WeakRef;
static int weak_ref_compare(const void *obj, const WeakRef weak_ref)
{
return (id) obj == weak_ref.obj;
}
static uint32_t ptr_hash(const void *ptr)
{
// Bit-rotate right 4, since the lowest few bits in an object pointer will
// always be 0, which is not so useful for a hash value
return ((uintptr_t)ptr >> 4) | ((uintptr_t)ptr << ((sizeof(id) * 8) - 4));
}
static int weak_ref_hash(const WeakRef weak_ref)
{
return ptr_hash(weak_ref.obj);
}
static int weak_ref_is_null(const WeakRef weak_ref)
{
return weak_ref.obj == NULL;
}
const static WeakRef NullWeakRef;
#define MAP_TABLE_NAME weak_ref
#define MAP_TABLE_COMPARE_FUNCTION weak_ref_compare
#define MAP_TABLE_HASH_KEY ptr_hash
#define MAP_TABLE_HASH_VALUE weak_ref_hash
#define MAP_TABLE_HASH_VALUE weak_ref_hash
#define MAP_TABLE_VALUE_TYPE struct objc_weak_ref
#define MAP_TABLE_VALUE_NULL weak_ref_is_null
#define MAP_TABLE_VALUE_PLACEHOLDER NullWeakRef
#define MAP_TABLE_ACCESS_BY_REFERENCE 1
#define MAP_TABLE_SINGLE_THREAD 1
#define MAP_TABLE_NO_LOCK 1
#include "hash_table.h"
static weak_ref_table *weakRefs;
mutex_t weakRefLock;
PRIVATE void init_arc(void)
{
weak_ref_initialize(&weakRefs, 128);
INIT_LOCK(weakRefLock);
#ifndef NO_PTHREADS
pthread_key_create(&ARCThreadKey, (void(*)(void*))cleanupPools);
#endif
}
void* block_load_weak(void *block);
id objc_storeWeak(id *addr, id obj)
{
id old = *addr;
LOCK_FOR_SCOPE(&weakRefLock);
if (nil != old)
{
WeakRef *oldRef = weak_ref_table_get(weakRefs, old);
while (NULL != oldRef)
{
for (int i=0 ; i<4 ; i++)
{
if (oldRef->ref[i] == addr)
{
oldRef->ref[i] = 0;
oldRef = 0;
break;
}
}
oldRef = (oldRef == NULL) ? NULL : oldRef->next;
}
}
if (nil == obj)
{
*addr = obj;
return nil;
}
Class cls = classForObject(obj);
if ((Class)&_NSConcreteGlobalBlock == cls)
{
// If this is a global block, it's never deallocated, so secretly make
// this a strong reference
// TODO: We probably also want to do the same for constant strings and
// classes.
*addr = obj;
return obj;
}
if ((Class)&_NSConcreteMallocBlock == cls)
{
obj = block_load_weak(obj);
}
else if (objc_test_class_flag(cls, objc_class_flag_fast_arc))
{
if ((*(((intptr_t*)obj) - 1)) < 0)
{
return nil;
}
}
else
{
obj = _objc_weak_load(obj);
}
if (nil != obj)
{
WeakRef *ref = weak_ref_table_get(weakRefs, obj);
while (NULL != ref)
{
for (int i=0 ; i<4 ; i++)
{
if (0 == ref->ref[i])
{
ref->ref[i] = addr;
*addr = obj;
return obj;
}
}
if (ref->next == NULL)
{
break;
}
ref = ref->next;
}
if (NULL != ref)
{
ref->next = calloc(sizeof(WeakRef), 1);
ref->next->ref[0] = addr;
}
else
{
WeakRef newRef = {0};
newRef.obj = obj;
newRef.ref[0] = addr;
weak_ref_insert(weakRefs, newRef);
}
}
*addr = obj;
return obj;
}
static void zeroRefs(WeakRef *ref, BOOL shouldFree)
{
if (NULL != ref->next)
{
zeroRefs(ref->next, YES);
}
for (int i=0 ; i<4 ; i++)
{
if (0 != ref->ref[i])
{
*ref->ref[i] = 0;
}
}
if (shouldFree)
{
free(ref);
}
else
{
memset(ref, 0, sizeof(WeakRef));
}
}
void objc_delete_weak_refs(id obj)
{
LOCK_FOR_SCOPE(&weakRefLock);
WeakRef *oldRef = weak_ref_table_get(weakRefs, obj);
if (0 != oldRef)
{
zeroRefs(oldRef, NO);
}
}
id objc_loadWeakRetained(id* addr)
{
LOCK_FOR_SCOPE(&weakRefLock);
id obj = *addr;
if (nil == obj) { return nil; }
Class cls = classForObject(obj);
if ((Class)&_NSConcreteMallocBlock == cls)
{
obj = block_load_weak(obj);
}
else if (objc_test_class_flag(cls, objc_class_flag_fast_arc))
{
if ((*(((intptr_t*)obj) - 1)) < 0)
{
return nil;
}
}
else
{
obj = _objc_weak_load(obj);
}
return objc_retain(obj);
}
id objc_loadWeak(id* object)
{
return objc_autorelease(objc_loadWeakRetained(object));
}
void objc_copyWeak(id *dest, id *src)
{
objc_release(objc_initWeak(dest, objc_loadWeakRetained(src)));
}
void objc_moveWeak(id *dest, id *src)
{
// Don't retain or release. While the weak ref lock is held, we know that
// the object can't be deallocated, so we just move the value and update
// the weak reference table entry to indicate the new address.
LOCK_FOR_SCOPE(&weakRefLock);
*dest = *src;
*src = nil;
WeakRef *oldRef = weak_ref_table_get(weakRefs, *dest);
while (NULL != oldRef)
{
for (int i=0 ; i<4 ; i++)
{
if (oldRef->ref[i] == src)
{
oldRef->ref[i] = dest;
return;
}
}
}
}
void objc_destroyWeak(id* obj)
{
objc_storeWeak(obj, nil);
}
id objc_initWeak(id *object, id value)
{
*object = nil;
return objc_storeWeak(object, value);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment