├── .cirrus.yml ├── .github ├── scripts │ ├── android_test_driver.sh │ └── android_test_main.sh └── workflows │ └── main.yml ├── .gitignore ├── ABIDoc └── abi.tex ├── ANNOUNCE ├── ANNOUNCE.1.0 ├── ANNOUNCE.1.1 ├── ANNOUNCE.1.2 ├── ANNOUNCE.1.3 ├── ANNOUNCE.1.4 ├── ANNOUNCE.1.5 ├── ANNOUNCE.1.6 ├── ANNOUNCE.1.6.1 ├── ANNOUNCE.1.7 ├── ANNOUNCE.1.8 ├── ANNOUNCE.1.8.1 ├── ANNOUNCE.1.9 ├── ANNOUNCE.2.0 ├── ANNOUNCE.2.1 ├── API ├── Block.h ├── Block_private.h ├── CMake ├── CMakeLists.txt └── typeinfo_test.cc ├── CMakeLists.txt ├── COPYING ├── Config.cmake.in ├── INSTALL ├── NSBlocks.m ├── README.md ├── README.windows ├── Test ├── ARCTest_arc.m ├── AllocatePair.m ├── AssociatedObject.m ├── AssociatedObject2.m ├── BlockImpTest.m ├── BlockTest_arc.m ├── BoxedForeignException.m ├── CMakeLists.txt ├── CXXException.cc ├── CXXException.m ├── Category.m ├── ConstantString.m ├── DirectMethods.m ├── ExceptionTest.m ├── FastARC.m ├── FastARCPool.m ├── FastPathAlloc.m ├── FastRefCount.m ├── ForeignException.m ├── Forward.m ├── ForwardDeclareProtocol.m ├── ForwardDeclareProtocolAccess.m ├── GNUmakefile ├── IVarOverlap.m ├── IVarSuperclassOverlap.m ├── ManyManySelectors.m ├── MethodArguments.m ├── NestedExceptions.m ├── NilException.m ├── ObjCXXEHInterop.m ├── ObjCXXEHInterop.mm ├── ObjCXXEHInteropTwice.mm ├── ObjCXXEHInterop_arc.m ├── ObjCXXEHInterop_arc.mm ├── PropertyAttributeTest.m ├── PropertyIntrospectionTest.m ├── PropertyIntrospectionTest2_arc.m ├── ProtocolCreation.m ├── ProtocolExtendedProperties.m ├── ResurrectInDealloc_arc.m ├── RuntimeTest.m ├── RuntimeTest.xcodeproj │ └── project.pbxproj ├── SuperMethodMissing.m ├── Test.h ├── Test.m ├── UnexpectedException.m ├── WeakBlock_arc.m ├── WeakImportClass.m ├── WeakRefLoad.m ├── WeakReferences_arc.m ├── alias.m ├── alignTest.m ├── category_properties.m ├── exchange.m ├── hash_table_delete.c ├── hash_test.c ├── ivar_arc.m ├── ivar_atomic.m ├── minRep1.mm ├── msgInterpose.m ├── objc_msgSend.m ├── objc_msgSend_WoA64.mm ├── setSuperclass.m └── zeroSizedIVar.m ├── abi_version.c ├── alias.h ├── alias_table.c ├── arc.mm ├── asmconstants.h ├── associate.m ├── block_to_imp.c ├── block_trampolines.S ├── blocks_runtime.h ├── blocks_runtime.m ├── blocks_runtime_np.m ├── buffer.h ├── builtin_classes.c ├── caps.c ├── category.h ├── category_loader.c ├── class.h ├── class_table.c ├── cmake_uninstall.cmake.in ├── common.S ├── constant_string.h ├── dtable.c ├── dtable.h ├── dwarf_eh.h ├── eh_personality.c ├── eh_trampoline.cc ├── eh_win32_msvc.cc ├── encoding2.c ├── fast_paths.m ├── gc_none.c ├── gc_ops.h ├── hash_table.h ├── hooks.c ├── ivar.c ├── ivar.h ├── legacy.c ├── legacy.h ├── legacy_malloc.c ├── libobjc.pc.in ├── loader.c ├── loader.h ├── lock.h ├── method.h ├── module.h ├── mutation.m ├── nsobject.h ├── objc ├── Availability.h ├── Object.h ├── Protocol.h ├── blocks_private.h ├── blocks_runtime.h ├── capabilities.h ├── developer.h ├── encoding.h ├── hooks.h ├── message.h ├── objc-api.h ├── objc-arc.h ├── objc-auto.h ├── objc-class.h ├── objc-config.h.in ├── objc-exception.h ├── objc-runtime.h ├── objc-visibility.h ├── objc.h ├── runtime-deprecated.h ├── runtime.h ├── slot.h └── toydispatch.h ├── objc_msgSend.S ├── objc_msgSend.aarch64.S ├── objc_msgSend.arm.S ├── objc_msgSend.mips.S ├── objc_msgSend.riscv64.S ├── objc_msgSend.x86-32.S ├── objc_msgSend.x86-64.S ├── objcxx_eh.cc ├── objcxx_eh.h ├── objcxx_eh_mingw.cc ├── objcxx_eh_private.h ├── pool.h ├── pool.hh ├── prepare_android_env.sh ├── properties.h ├── properties.m ├── protocol.c ├── protocol.h ├── runtime.c ├── safewindows.h ├── sarray2.c ├── sarray2.h ├── selector.h ├── selector_table.cc ├── sendmsg2.c ├── spinlock.h ├── statics_loader.c ├── string_hash.h ├── type_encoding_cases.h ├── unwind-arm.h ├── unwind-itanium.h ├── unwind.h └── visibility.h /.cirrus.yml: -------------------------------------------------------------------------------- 1 | libcxxrt_freebsd_task: 2 | matrix: 3 | - freebsd_instance: 4 | image_family: freebsd-13-5 5 | - freebsd_instance: 6 | image_family: freebsd-15-0-snap 7 | - freebsd_instance: 8 | image_family: freebsd-14-2 9 | 10 | install_script: pkg install -y cmake ninja git 11 | 12 | clone_script: | 13 | if [ -z "$CIRRUS_PR" ]; then 14 | git clone --recursive --branch=$CIRRUS_BRANCH https://x-access-token:${CIRRUS_REPO_CLONE_TOKEN}@github.com/${CIRRUS_REPO_FULL_NAME}.git $CIRRUS_WORKING_DIR 15 | git reset --hard $CIRRUS_CHANGE_IN_REPO 16 | else 17 | git clone --recursive https://x-access-token:${CIRRUS_REPO_CLONE_TOKEN}@github.com/${CIRRUS_REPO_FULL_NAME}.git $CIRRUS_WORKING_DIR 18 | git fetch origin pull/$CIRRUS_PR/head:pull/$CIRRUS_PR 19 | git reset --hard $CIRRUS_CHANGE_IN_REPO 20 | fi 21 | git submodule sync 22 | git submodule update 23 | 24 | build_script: | 25 | mkdir Build 26 | cd Build 27 | cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ 28 | ninja 29 | 30 | test_script: cd Build && ctest -j4 31 | 32 | libcxxrt_master_task: 33 | freebsd_instance: 34 | image_family: freebsd-14-2 35 | install_script: pkg install -y cmake ninja git 36 | 37 | clone_script: | 38 | if [ -z "$CIRRUS_PR" ]; then 39 | git clone --recursive --branch=$CIRRUS_BRANCH https://x-access-token:${CIRRUS_REPO_CLONE_TOKEN}@github.com/${CIRRUS_REPO_FULL_NAME}.git $CIRRUS_WORKING_DIR 40 | git reset --hard $CIRRUS_CHANGE_IN_REPO 41 | else 42 | git clone --recursive https://x-access-token:${CIRRUS_REPO_CLONE_TOKEN}@github.com/${CIRRUS_REPO_FULL_NAME}.git $CIRRUS_WORKING_DIR 43 | git fetch origin pull/$CIRRUS_PR/head:pull/$CIRRUS_PR 44 | git reset --hard $CIRRUS_CHANGE_IN_REPO 45 | fi 46 | git submodule sync 47 | git submodule update 48 | 49 | install_libcxxrt_script: | 50 | git clone https://github.com/libcxxrt/libcxxrt.git 51 | mkdir -p libcxxrt/Build 52 | cd libcxxrt/Build 53 | cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ 54 | ninja 55 | cp lib/libcxxrt.so /usr/local/lib 56 | 57 | build_script: | 58 | mkdir Build 59 | cd Build 60 | cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ 61 | ninja 62 | 63 | test_script: cd Build && ctest -j4 64 | -------------------------------------------------------------------------------- /.github/scripts/android_test_driver.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This script is run on the emulator to run the tests 4 | 5 | # Get list of all binaries in pwd for later iteration (only include binaries) 6 | BINARIES=$(find . -maxdepth 1 -type f ! -name "*.so" ! -name "android_test_driver.sh") 7 | 8 | TOTAL=0 9 | PASS=0 10 | SKIP=0 11 | FAIL=0 12 | 13 | # Run each binary, measure time and return value (PASS or FAIL). Print stdout and stderr only after a failure 14 | for BINARY in $BINARIES; do 15 | TOTAL=$((TOTAL + 1)) 16 | 17 | START_TIME=$(date +%s) 18 | # Busybox date does not support %N, so we can't get milliseconds this way 19 | #START_TIME_MS=$((START_TIME * 1000 + $(date +%N) / 1000000)) 20 | 21 | OUTPUT=$("$BINARY" 2>&1) 22 | EXIT_CODE=$? 23 | 24 | END_TIME=$(date +%s) 25 | #END_TIME_MS=$((END_TIME * 1000 + $(date +%N) / 1000000)) 26 | #ELAPSED_TIME=$((END_TIME_MS - START_TIME_MS)) 27 | ELAPSED_TIME=$((END_TIME - START_TIME)) 28 | 29 | BINARY_NAME=$(basename "$BINARY") 30 | 31 | if [ $EXIT_CODE -eq 0 ]; then 32 | PASS=$((PASS + 1)) 33 | echo "PASSED ($EXIT_CODE): $BINARY_NAME (${ELAPSED_TIME}s)" 34 | elif [ $EXIT_CODE -eq 77 ]; then 35 | SKIP=$((SKIP + 1)) 36 | echo "SKIPPED: $BINARY_NAME" 37 | else 38 | FAIL=$((FAIL + 1)) 39 | echo "FAILED ($EXIT_CODE): $BINARY_NAME (${ELAPSED_TIME}s)" 40 | if [ -z "$OUTPUT" ]; then 41 | echo "No output written to stdout." 42 | else 43 | echo "Output:" 44 | echo "$OUTPUT" 45 | fi 46 | fi 47 | done 48 | 49 | if [ $TOTAL -eq 0 ]; then 50 | echo "No tests found. Exiting." 51 | exit 1 52 | fi 53 | 54 | PERCENTAGE=$(((PASS + SKIP) * 100 / TOTAL)) 55 | echo "$PERCENTAGE% Passed. Total: $TOTAL, Passed: $PASS, Skipped: $SKIP, Failed: $FAIL" 56 | echo "Finished running tests. Exiting." 57 | 58 | # Exit with corresponding return value 59 | if [ $FAIL -eq 0 ]; then 60 | exit 0 61 | else 62 | exit 1 63 | fi 64 | -------------------------------------------------------------------------------- /.github/scripts/android_test_main.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | main () { 4 | # first argument is the build directory 5 | local BUILD_DIR=$1 6 | # second argument is the android ndk sysroot 7 | local ANDROID_NDK_SYSROOT=$2 8 | # third argument is the target triple 9 | # e.g. arm-linux-androideabi, aarch64-linux-android, x86_64-linux-android 10 | local TARGET_TRIPLE=$3 11 | 12 | if [ ! -d "$BUILD_DIR" ] 13 | then 14 | echo "Build directory argument not found" 15 | exit 1 16 | fi 17 | if [ ! -d "$ANDROID_NDK_SYSROOT" ] 18 | then 19 | echo "Android NDK sysroot argument not found" 20 | exit 1 21 | fi 22 | if [ -z "$TARGET_TRIPLE" ] 23 | then 24 | echo "Target triple argument not found" 25 | exit 1 26 | fi 27 | 28 | # We need to run the emulator with root permissions 29 | # This is needed to run the tests 30 | adb root 31 | 32 | local TEMP_DIR=$(mktemp -d) 33 | 34 | # Copy libobjc.so and test binaries to temporary directory 35 | cp $BUILD_DIR/libobjc.so* $TEMP_DIR 36 | cp $BUILD_DIR/Test/* $TEMP_DIR 37 | 38 | for file in $TEMP_DIR/*; do 39 | # Check if file is a binary 40 | if ! file $file | grep -q "ELF" 41 | then 42 | rm $file 43 | continue 44 | fi 45 | 46 | # Set runtime path to ORIGIN 47 | patchelf --set-rpath '$ORIGIN' $file 48 | done 49 | 50 | # Copy libc++_shared.so (required by libobjc2) 51 | cp $ANDROID_NDK_SYSROOT/usr/lib/$TARGET_TRIPLE/libc++_shared.so $TEMP_DIR 52 | 53 | adb shell rm -rf /data/local/tmp/libobjc2_tests 54 | adb push $TEMP_DIR /data/local/tmp/libobjc2_tests 55 | 56 | # Copy android_test_driver.sh to device 57 | adb push $BUILD_DIR/../.github/scripts/android_test_driver.sh /data/local/tmp/libobjc2_tests 58 | 59 | # Run the tests 60 | adb shell "cd /data/local/tmp/libobjc2_tests && sh android_test_driver.sh" 61 | } 62 | 63 | main "$@" 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | .*.sw? 3 | [b|B]uild 4 | Debug 5 | Release 6 | -------------------------------------------------------------------------------- /ANNOUNCE: -------------------------------------------------------------------------------- 1 | GNUstep Objective-C Runtime 2.2 2 | =============================== 3 | 4 | This is the second update to the second major release of the GNUstep Objective-C 5 | runtime (a.k.a. libobjc2). This runtime was designed to support the features 6 | of modern dialects of Objective-C for use with GNUstep and other Objective-C 7 | programs. 8 | 9 | Highlights of this release include: 10 | 11 | - Initial support for RISC-V 64-bit (rv64) including an architecture-specific 12 | objc_msgSend, and block trampoline implementation. Please note that 13 | double-precision floating-point support (rv64d) is required for the 14 | objc_msgSend implementation. 15 | - Initial support for Windows on ARM64 with fast-path objc_msgSend. 16 | - Numerous improvements to the Objective-C++ exception interoperation code. 17 | The runtime now dynamically detects whether the libcxxrt, libsupc++, or 18 | libc++abi variant of the Itanium C++ Exception ABI is being used. This is 19 | the first version to support exception interoperability with libc++abi. 20 | - Because we no longer need to identify the specific C++ runtime, we can link 21 | to it indirectly via the C++ standard library, which enables more C++ to be 22 | used in the Objective-C runtime. 23 | - The minimum CMake version has been bumped to 3.16, which supports 24 | Objective-C. This support is now used, simplifying the build. 25 | - Support for GC mode is gone. Apple dropped support for this a long time ago. 26 | - `objc_setUncaughtExceptionHandler` is added, which avoids consuming code 27 | needing to access a library-owned global. 28 | - The selector-table code has been rewritten in C++, improving performance of 29 | adding selectors. This is unlikely to have a measurable impact on 30 | performance outside of contrived test cases, but the new code is more 31 | maintainable. 32 | - Several bug fixes in the ARC code, especially in corner cases surrounding 33 | weak references. 34 | - Support for fast-path allocation / initialisation functions. Root classes 35 | that opt into this should implement `+_TrivialAllocInit` (this can be an 36 | empty method, it is not called). Clang 18 or later will emit calls to the 37 | fast-path functions for `+alloc`, `+allocWithZone:` and `+alloc` + `-init` 38 | calls. This should improve code density as well as performance. 39 | 40 | You may obtain the code for this release from git and use the 2.2 branch: 41 | 42 | https://github.com/gnustep/libobjc2.git 43 | 44 | Alternatively, a tarball is available from: 45 | 46 | https://github.com/gnustep/libobjc2/archive/v2.2.zip 47 | https://github.com/gnustep/libobjc2/archive/v2.2.tar.gz 48 | 49 | The runtime library is responsible for implementing the core features of the 50 | object model, as well as exposing introspection features to the user. The 51 | GNUstep runtime implements a superset of Apple's Objective-C Runtime APIs. 52 | 53 | If you come across any problems, please file them in the issue tracker: 54 | 55 | https://github.com/gnustep/libobjc2/issues 56 | -------------------------------------------------------------------------------- /ANNOUNCE.1.0: -------------------------------------------------------------------------------- 1 | GNUstep Objective-C Runtime 1.0 2 | =============================== 3 | 4 | This is the first official release of the GNUstep Objective-C runtime (a.k.a. 5 | libobjc2). This runtime was designed to support the features of Objective-C 2 6 | for use with GNUstep and other Objective-C programs. 7 | 8 | You may obtain the code for this release from subversion at the following 9 | subversion branch: 10 | 11 | svn://svn.gna.org/svn/gnustep/libs/libobjc2/1.0 12 | 13 | Alternatively, a tarball is available from: 14 | 15 | http://download.gna.org/gnustep/libobjc2-1.0.tar.bz2 16 | 17 | The runtime library is responsible for implementing the core features of the 18 | object model, as well as exposing introspection features to the user. The 19 | GNUstep runtime implements Apple's Objective-C Runtime APIs, and a small number 20 | of GCC APIs for legacy compatibility. 21 | 22 | This library is based on the Étoilé Objective-C Runtime, an earlier research 23 | prototype, and includes support for non-fragile instance variables, 24 | type-dependent dispatch, and object planes. It is fully compatible with the 25 | FSF's GCC Objective-C ABI and also implements a new ABI that is supported by 26 | Clang and is required for some of the newer features. 27 | 28 | Although the runtime has been tested by several people, and is being used 29 | extensively by the Étoilé project, it is entirely new (MIT licensed) code and 30 | may still contain bugs. If you come across any problems, please report them to 31 | the GNUstep Developer mailing list . A 1.1 release, 32 | fixing any bugs that are encountered in wider deployment, is planned to 33 | coincide with the next GNUstep release. 34 | -------------------------------------------------------------------------------- /ANNOUNCE.1.1: -------------------------------------------------------------------------------- 1 | GNUstep Objective-C Runtime 1.1 2 | =============================== 3 | 4 | This is the second official release of the GNUstep Objective-C runtime (a.k.a. 5 | libobjc2). This runtime was designed to support the features of Objective-C 2 6 | for use with GNUstep and other Objective-C programs. This release contains 7 | minor bug fixes and provides compatibility with synthesised declared properties 8 | from GCC 4.6 and recent versions of clang. 9 | 10 | You may obtain the code for this release from subversion at the following 11 | subversion branch: 12 | 13 | svn://svn.gna.org/svn/gnustep/libs/libobjc2/1.1 14 | 15 | Alternatively, a tarball is available from: 16 | 17 | http://download.gna.org/gnustep/libobjc2-1.1.tar.bz2 18 | 19 | The runtime library is responsible for implementing the core features of the 20 | object model, as well as exposing introspection features to the user. The 21 | GNUstep runtime implements Apple's Objective-C Runtime APIs, and a small number 22 | of GCC APIs for legacy compatibility. 23 | 24 | This library is based on the Étoilé Objective-C Runtime, an earlier research 25 | prototype, and includes support for non-fragile instance variables, 26 | type-dependent dispatch, and object planes. It is fully compatible with the 27 | FSF's GCC Objective-C ABI and also implements a new ABI that is supported by 28 | Clang and is required for some of the newer features. 29 | 30 | Although the runtime has been tested by several people, and is being used 31 | extensively by the Étoilé project, it is entirely new (MIT licensed) code and 32 | may still contain bugs. If you come across any problems, please report them to 33 | the GNUstep Developer mailing list . 34 | -------------------------------------------------------------------------------- /ANNOUNCE.1.2: -------------------------------------------------------------------------------- 1 | GNUstep Objective-C Runtime 1.2 2 | =============================== 3 | 4 | This is the 1.2 release of the GNUstep Objective-C runtime (a.k.a. 5 | libobjc2). This runtime was designed to support the features of Objective-C 2 6 | for use with GNUstep and other Objective-C programs. This release contains 7 | several bug fixes, and is tested with the current GNUstep trunk, so will be 8 | compatible with the upcoming GNUstep release. 9 | 10 | You may obtain the code for this release from subversion at the following 11 | subversion branch: 12 | 13 | svn://svn.gna.org/svn/gnustep/libs/libobjc2/1.2 14 | 15 | Alternatively, a tarball is available from: 16 | 17 | http://download.gna.org/gnustep/libobjc2-1.2.tar.bz2 18 | 19 | The runtime library is responsible for implementing the core features of the 20 | object model, as well as exposing introspection features to the user. The 21 | GNUstep runtime implements Apple's Objective-C Runtime APIs, and a small number 22 | of GCC APIs for legacy compatibility. 23 | 24 | This library is based on the Étoilé Objective-C Runtime, an earlier research 25 | prototype, and includes support for non-fragile instance variables, 26 | type-dependent dispatch, and object planes. It is fully compatible with the 27 | FSF's GCC Objective-C ABI and also implements a new ABI that is supported by 28 | Clang and is required for some of the newer features. 29 | 30 | Although the runtime has been tested by several people, and is being used 31 | extensively by the Étoilé project, it is entirely new (MIT licensed) code and 32 | may still contain bugs. If you come across any problems, please report them to 33 | the GNUstep Developer mailing list . 34 | -------------------------------------------------------------------------------- /ANNOUNCE.1.3: -------------------------------------------------------------------------------- 1 | GNUstep Objective-C Runtime 1.3 2 | =============================== 3 | 4 | This is the fourth official release of the GNUstep Objective-C runtime (a.k.a. 5 | libobjc2). This runtime was designed to support the features of Objective-C 2 6 | for use with GNUstep and other Objective-C programs. 7 | 8 | This release contains several bug fixes and includes a unified exception 9 | model, providing the same features as Apple's Modern runtime for Objective-C++ 10 | code, specifically the ability to throw Objective-C objects with @throw() or 11 | throw() and catch them with @catch() or catch(). The new unified exception 12 | model is supported by Clang 2.9 and is compatible with Apple's Objective-C++ 13 | exception behaviour. Another enhancement in this release is the addition of 14 | support for class aliases. This provides a run-time equivalent of 15 | @compatibility_alias, allowing a class to show up in class lookup searching for 16 | its alias. 17 | 18 | You may obtain the code for this release from subversion at the following 19 | subversion branch: 20 | 21 | svn://svn.gna.org/svn/gnustep/libs/libobjc2/1.3 22 | 23 | Alternatively, a tarball is available from: 24 | 25 | http://download.gna.org/gnustep/libobjc2-1.3.tar.bz2 26 | 27 | The runtime library is responsible for implementing the core features of the 28 | object model, as well as exposing introspection features to the user. The 29 | GNUstep runtime implements Apple's Objective-C Runtime APIs, and a small number 30 | of GCC APIs for legacy compatibility. 31 | 32 | This library is based on the Étoilé Objective-C Runtime, an earlier research 33 | prototype, and includes support for non-fragile instance variables, 34 | type-dependent dispatch, and object planes. It is fully compatible with the 35 | FSF's GCC Objective-C ABI and also implements a new ABI that is supported by 36 | Clang and Étoilé's LanguageKit and is required for some of the newer features. 37 | 38 | Although the runtime has been tested by several people, and is being used 39 | extensively by the Étoilé project, it is entirely new (MIT licensed) code and 40 | may still contain bugs. If you come across any problems, please report them to 41 | the GNUstep Developer mailing list . 42 | -------------------------------------------------------------------------------- /ANNOUNCE.1.5: -------------------------------------------------------------------------------- 1 | GNUstep Objective-C Runtime 1.5 2 | =============================== 3 | 4 | This is the sixth official release of the GNUstep Objective-C runtime (a.k.a. 5 | libobjc2). This runtime was designed to support the features of Objective-C 2 6 | for use with GNUstep and other Objective-C programs. Highlights of this 7 | release include: 8 | 9 | - Support for Apple-compatible garbage collection APIs, along with extensions 10 | to support CoreFoundation-style explicit reference counting in a garbage 11 | collected environment. This uses the Boehm garbage collector and is enabled 12 | by specifying boehm_gc=yes when building. This requires version 7.1 or later 13 | of libgc. Code compiled with -fobjc-gc can be mixed with code that 14 | implements normal reference counting and with code compiled with 15 | -fobjc-gc-only. The runtime supports both GC and non-GC code when compiled 16 | with GC support and will automatically select the correct behavior depending 17 | on the loaded code. 18 | 19 | - The runtime will now use Boehm GC for several internal data structures, if it 20 | is built with GC enabled. This avoids the need for defensive programming 21 | with respect to thread safety in several places. 22 | 23 | - This is the first release to provide a superset of the functionality provided 24 | by the Mac Objective-C runtime, as shipped with OS X 10.6. 25 | 26 | - Full support for Automatic Reference Counting (ARC), compatible with OS X 27 | 10.7 and iOS 5, including support for __weak references. 28 | 29 | - The LLVM optimisation passes have been improved and better tested. Code 30 | compiled with them now passes the EtoileFoundation test suite. 31 | 32 | You may obtain the code for this release from subversion at the following 33 | subversion branch: 34 | 35 | svn://svn.gna.org/svn/gnustep/libs/libobjc2/1.5 36 | 37 | Alternatively, a tarball is available from: 38 | 39 | http://download.gna.org/gnustep/libobjc2-1.5.tar.bz2 40 | 41 | The runtime library is responsible for implementing the core features of the 42 | object model, as well as exposing introspection features to the user. The 43 | GNUstep runtime implements Apple's Objective-C Runtime APIs, and a small number 44 | of GCC APIs for legacy compatibility. 45 | 46 | This library is based on the Étoilé Objective-C Runtime, an earlier research 47 | prototype, and includes support for non-fragile instance variables, 48 | type-dependent dispatch, and object planes. It is fully compatible with the 49 | FSF's GCC Objective-C ABI and also implements a new ABI that is supported by 50 | Clang and Étoilé's LanguageKit and is required for some of the newer features. 51 | 52 | Although the runtime has been tested by several people, and is being used 53 | extensively by the Étoilé project, it is entirely new (MIT licensed) code and 54 | may still contain bugs. If you come across any problems, please report them to 55 | the GNUstep Developer mailing list . 56 | -------------------------------------------------------------------------------- /ANNOUNCE.1.6: -------------------------------------------------------------------------------- 1 | GNUstep Objective-C Runtime 1.6 2 | =============================== 3 | 4 | This is the seventh official release of the GNUstep Objective-C runtime (a.k.a. 5 | libobjc2). This runtime was designed to support the features of Objective-C 2 6 | for use with GNUstep and other Objective-C programs. Highlights of this 7 | release include: 8 | 9 | - Compatibility with the new runtime APIs introduced with Mac OS X 10.7 / iOS 5. 10 | 11 | - Support for small objects (ones hidden inside a pointer). On 32-bit systems, 12 | the runtime permits one small object class, on 64-bit systems it permits 4. 13 | This is used by GNUstep for small NSNumber and NSString instances, and these 14 | are used by LanguageKit for message sending to small integers. 15 | 16 | - Support for prototype-style object orientation. You can now add methods, as 17 | well as associated references, to individual objects, and clone them. The 18 | runtime now supports everything required for the JavaScript object model, 19 | including the ability to use blocks as methods on x86, x86-64 and ARM. 20 | 21 | - Support for Apple-compatible objc_msgSend() functions for x86, x86-64, and 22 | ARM. Using these approximately halves the cost of message sending operations 23 | and results in a 10% smaller total binary size. 24 | 25 | - A fully maintained POSIX Makefile to make bootstrapping builds and packaging 26 | easier. This will be used automatically if GNUstep Make is not installed. 27 | 28 | - Improvements to the included LLVM optimisation passes. Testing on a 2.8GHz 29 | Xeon, a loop of 200,000,000 class messages took 0.8 seconds with all 30 | optimisations enabled (including speculative inlining). With -Os, the test 31 | took 2 seconds. With explicit IMP caching in the source code, the test took 32 | 1.2 seconds. For reference, the same test using the GCC Objective-C runtime 33 | took 11 seconds (when compiled with either Clang/LLVM or GCC). 34 | 35 | Various features of this release required some per-platform assembly code. For 36 | the 1.6.0 release, ARM, x86 and x86-64 (with the SysV ABI, not with the Win64 37 | ABI) are supported. Future releases in the 1.6.x series will extend this to 38 | other architectures. 39 | 40 | You may obtain the code for this release from subversion at the following 41 | subversion branch: 42 | 43 | svn://svn.gna.org/svn/gnustep/libs/libobjc2/1.6 44 | 45 | Alternatively, a tarball is available from: 46 | 47 | http://download.gna.org/gnustep/libobjc2-1.6.tar.bz2 48 | 49 | The runtime library is responsible for implementing the core features of the 50 | object model, as well as exposing introspection features to the user. The 51 | GNUstep runtime implements Apple's Objective-C Runtime APIs, and a small number 52 | of GCC APIs for legacy compatibility. 53 | 54 | This library is based on the Étoilé Objective-C Runtime, an earlier research 55 | prototype, and includes support for non-fragile instance variables, 56 | type-dependent dispatch, and object planes. It is fully backwards compatible 57 | with the FSF's GCC 4.2.1 Objective-C ABI and also implements a new ABI that is 58 | supported by Clang and Étoilé's LanguageKit and is required for some of the 59 | newer features. 60 | 61 | Although the runtime has been tested by several people, and is being used 62 | extensively by the Étoilé project, it is relatively new code and may still 63 | contain bugs. If you come across any problems, please report them to the 64 | GNUstep Developer mailing list . 65 | -------------------------------------------------------------------------------- /ANNOUNCE.1.6.1: -------------------------------------------------------------------------------- 1 | GNUstep Objective-C Runtime 1.6.1 2 | ================================= 3 | 4 | This is a point release to the seventh official release of the GNUstep 5 | Objective-C runtime (a.k.a. libobjc2). This runtime was designed to support 6 | the features of Objective-C 2 for use with GNUstep and other Objective-C 7 | programs. Highlights of this release include: 8 | 9 | - Improved support for ARC autorelease pools. 10 | 11 | - Some small bug fixes in blocks support. 12 | 13 | - Improvements to the Objective-C++ unified exception model support. 14 | 15 | - Updated optimisation passes to work with LLVM 3.1 16 | 17 | You may obtain the code for this release from subversion at the following 18 | subversion branch: 19 | 20 | svn://svn.gna.org/svn/gnustep/libs/libobjc2/1.6.1 21 | 22 | Alternatively, a tarball is available from: 23 | 24 | http://download.gna.org/gnustep/libobjc2-1.6.1.tar.bz2 25 | 26 | The runtime library is responsible for implementing the core features of the 27 | object model, as well as exposing introspection features to the user. The 28 | GNUstep runtime implements Apple's Objective-C Runtime APIs, and a small number 29 | of GCC APIs for legacy compatibility. 30 | 31 | This library is based on the Étoilé Objective-C Runtime, an earlier research 32 | prototype, and includes support for non-fragile instance variables, 33 | type-dependent dispatch, and object planes. It is fully backwards compatible 34 | with the FSF's GCC 4.2.1 Objective-C ABI and also implements a new ABI that is 35 | supported by Clang and Étoilé's LanguageKit and is required for some of the 36 | newer features. 37 | 38 | Although the runtime has been tested by several people, and is being used 39 | extensively by the Étoilé project, it is relatively new code and may still 40 | contain bugs. If you come across any problems, please report them to the 41 | GNUstep Developer mailing list . 42 | -------------------------------------------------------------------------------- /ANNOUNCE.1.7: -------------------------------------------------------------------------------- 1 | GNUstep Objective-C Runtime 1.7 2 | =============================== 3 | 4 | This is a point release to the eighth official release of the GNUstep 5 | Objective-C runtime (a.k.a. libobjc2). This runtime was designed to support 6 | the features of modern dialects of Objective-C for use with GNUstep and other 7 | Objective-C programs. Highlights of this release include: 8 | 9 | - A new CMake-based build system. This makes all of the configurable options 10 | available via a clean interface. CPack is supported for building RPM and DEB 11 | packages out of the box. 12 | 13 | - A new CTest-based test suite, replacing the old ad-hoc tests. 14 | 15 | - Build a single libobjc with support for Objective-C++ on platforms where a 16 | C++ ABI library (libcxxrt or libsupc++) is installed as a shared library. 17 | 18 | - Added specialised property accessor functions and support for atomic 19 | properties with C++ non-POD types. 20 | 21 | - Significant improvements in property introspection and an exhaustive test 22 | suite. 23 | 24 | - Improved integration with libdispatch. The runtime will correctly register 25 | work queues with the garbage collector or create autorelease pools around 26 | block invocations. 27 | 28 | - A new exception implementation providing better integration with foreign 29 | exceptions (e.g. C++ exceptions). The new ABI is supported by clang 3.3 when 30 | compiling with -fobjc-runtime=gnustep-1.7 (or higher). The old ABI is still 31 | supported and both can be used within the same program, however code compiled 32 | with the old ABI remains unreliable in the presence of foreign exceptions. 33 | It is strongly recommended that anyone using exceptions with Objective-C++ 34 | switches to the new version. 35 | 36 | - MIPS64 support in the assembly routines. Currently these are only tested 37 | with the n64 ABI. They are believed to work with n32 and o32, but should be 38 | considered unsupported on these platforms. 39 | 40 | - Small algorithmic improvement to the objc_msgSend() implementation, giving 41 | approximately a 10% speedup (architecture-dependent) on message sends. 42 | 43 | - Updated optimisation passes to work with LLVM 3.2 and recent LLVM trunk. 44 | 45 | 46 | You may obtain the code for this release from subversion at the following 47 | subversion branch: 48 | 49 | svn://svn.gna.org/svn/gnustep/libs/libobjc2/releases/1.7 50 | 51 | Alternatively, a tarball is available from: 52 | 53 | http://download.gna.org/gnustep/libobjc2-1.7.tar.bz2 54 | 55 | The runtime library is responsible for implementing the core features of the 56 | object model, as well as exposing introspection features to the user. The 57 | GNUstep runtime implements Apple's Objective-C Runtime APIs, and a small number 58 | of GCC APIs for legacy compatibility. 59 | 60 | This library is based on the Étoilé Objective-C Runtime, an earlier research 61 | prototype, and includes support for non-fragile instance variables, 62 | type-dependent dispatch, and object planes. It is fully backwards compatible 63 | with the FSF's GCC 4.2.1 Objective-C ABI and also implements a new ABI that is 64 | supported by Clang and Étoilé's LanguageKit and is required for some of the 65 | newer features. 66 | 67 | If you come across any problems, please report them to the GNUstep Developer 68 | mailing list . 69 | -------------------------------------------------------------------------------- /ANNOUNCE.1.8: -------------------------------------------------------------------------------- 1 | GNUstep Objective-C Runtime 1.8 2 | =============================== 3 | 4 | This the ninth official release of the GNUstep Objective-C runtime (a.k.a. 5 | libobjc2). This runtime was designed to support the features of modern 6 | dialects of Objective-C for use with GNUstep and other Objective-C programs. 7 | Highlights of this release include: 8 | 9 | - Added API for tracing, allowing interposition on all message sends matching a 10 | given selector. 11 | 12 | - Numerous bug fixes and stability improvements. 13 | 14 | You may obtain the code for this release from git and use the 1.8 branch: 15 | 16 | https://github.com/gnustep/libobjc2.git 17 | 18 | Alternatively, a tarball is available from: 19 | 20 | https://github.com/gnustep/libobjc2/archive/v1.8.zip 21 | https://github.com/gnustep/libobjc2/archive/v1.8.tar.gz 22 | 23 | The runtime library is responsible for implementing the core features of the 24 | object model, as well as exposing introspection features to the user. The 25 | GNUstep runtime implements Apple's Objective-C Runtime APIs, and a small number 26 | of GCC APIs for legacy compatibility. 27 | 28 | This library is based on the Étoilé Objective-C Runtime, an earlier research 29 | prototype, and includes support for non-fragile instance variables, 30 | type-dependent dispatch, and object planes. It is fully backwards compatible 31 | with the FSF's GCC 4.2.1 Objective-C ABI and also implements a new ABI that is 32 | supported by Clang and Étoilé's LanguageKit and is required for some of the 33 | newer features. 34 | 35 | If you come across any problems, please file them in the issue tracker: 36 | 37 | https://github.com/gnustep/libobjc2/issues 38 | -------------------------------------------------------------------------------- /ANNOUNCE.1.8.1: -------------------------------------------------------------------------------- 1 | GNUstep Objective-C Runtime 1.8.1 2 | ================================= 3 | 4 | This a bugfix release for the ninth official release of the GNUstep Objective-C 5 | runtime (a.k.a. libobjc2). This runtime was designed to support the features 6 | of modern dialects of Objective-C for use with GNUstep and other Objective-C 7 | programs. Highlights of this release include: 8 | 9 | - Better build system detection of LLVM not being present 10 | 11 | - Fix for a bug causing corruption of runtime state when hidden classes are 12 | deallocated. 13 | 14 | You may obtain the code for this release from git and use the 1.8 branch: 15 | 16 | https://github.com/gnustep/libobjc2.git 17 | 18 | Alternatively, a tarball is available from: 19 | 20 | https://github.com/gnustep/libobjc2/archive/v1.8.zip 21 | https://github.com/gnustep/libobjc2/archive/v1.8.tar.gz 22 | 23 | The runtime library is responsible for implementing the core features of the 24 | object model, as well as exposing introspection features to the user. The 25 | GNUstep runtime implements Apple's Objective-C Runtime APIs, and a small number 26 | of GCC APIs for legacy compatibility. 27 | 28 | This library is based on the Étoilé Objective-C Runtime, an earlier research 29 | prototype, and includes support for non-fragile instance variables, 30 | type-dependent dispatch, and object planes. It is fully backwards compatible 31 | with the FSF's GCC 4.2.1 Objective-C ABI and also implements a new ABI that is 32 | supported by Clang and Étoilé's LanguageKit and is required for some of the 33 | newer features. 34 | 35 | If you come across any problems, please file them in the issue tracker: 36 | 37 | https://github.com/gnustep/libobjc2/issues 38 | -------------------------------------------------------------------------------- /ANNOUNCE.1.9: -------------------------------------------------------------------------------- 1 | GNUstep Objective-C Runtime 1.9 2 | =============================== 3 | 4 | This the ninth official release of the GNUstep Objective-C runtime (a.k.a. 5 | libobjc2). This runtime was designed to support the features of modern 6 | dialects of Objective-C for use with GNUstep and other Objective-C programs. 7 | Highlights of this release include: 8 | 9 | - Support for 64-bit ARM (AArch64) processors, including assembly fast paths 10 | for message sending. 11 | 12 | - Improved the dispatch table representation to improve performance and cache 13 | usage on the fast path. 14 | 15 | - The implementation of `imp_implementationWithBlock`, the function that allows 16 | blocks to be used as methods, no longer requires physical pages to be mapped 17 | both writeable and executable. 18 | 19 | - Numerous improvements to the interaction between runtime functions and ARC. 20 | 21 | - Support for Thumb-2 interworking on ARM. Note that the library must be 22 | compiled for ARMv7 or ARMv6T2 for this code to be enabled. Once it has been, 23 | other Objective-C binaries linked with the library can be compiled as ARM or 24 | Thumb-2 code. This will also generate Thumb-2 message send functions, 25 | improving instruction cache usage. 26 | 27 | - Significant improvements to ARC, including 28 | 29 | * The runtime no longer acquires a global lock on every object deallocation (a 30 | global lock is still used for objects that have weak references). *NOTE:* 31 | This is incompatible with other code directly inspecting the reference 32 | count and will break with older versions of GNUstep Base! 33 | 34 | * Weak references use a scheme closer to C++ `std::weak_pointer` and are 35 | lazily zeroed on access. This reduces the space overheads for weak 36 | references. 37 | 38 | * Some additional helper functions are added for use in `NSObject` and other 39 | root classes, which simplifies the layering between the runtime and the 40 | Foundation (or equivalent) implementation. 41 | 42 | - Improvements to how the runtime handles layout of ivars with strong alignment 43 | requirements, which should fix issues relating to using vector types in 44 | Objective-C objects. 45 | 46 | - The option to build a separate libobjcxx has been removed. The runtime will 47 | now depend on the C++ standard library implementation if no useable C++ 48 | runtime is available. Note that C++ exception interworking does not work 49 | because LLVM's libc++abi (shipped by Apple) does not provide GNU-compatible 50 | hooks and so Objective-C++ exception support will be automatically disabled 51 | on this platform. Any other platforms shipping libc++abi should consider 52 | either GNU libsupc++ or libcxxrt as an alternative. 53 | 54 | You may obtain the code for this release from git and use the 1.9 branch: 55 | 56 | https://github.com/gnustep/libobjc2.git 57 | 58 | Alternatively, a tarball is available from: 59 | 60 | https://github.com/gnustep/libobjc2/archive/v1.9.zip 61 | https://github.com/gnustep/libobjc2/archive/v1.9.tar.gz 62 | 63 | The runtime library is responsible for implementing the core features of the 64 | object model, as well as exposing introspection features to the user. The 65 | GNUstep runtime implements Apple's Objective-C Runtime APIs, and a small number 66 | of GCC APIs for legacy compatibility. 67 | 68 | This library is based on the Étoilé Objective-C Runtime, an earlier research 69 | prototype, and includes support for non-fragile instance variables, 70 | type-dependent dispatch, and object planes. It is fully backwards compatible 71 | with the FSF's GCC 4.2.1 Objective-C ABI and also implements a new ABI that is 72 | supported by Clang and Étoilé's LanguageKit and is required for some of the 73 | newer features. 74 | 75 | If you come across any problems, please file them in the issue tracker: 76 | 77 | https://github.com/gnustep/libobjc2/issues 78 | -------------------------------------------------------------------------------- /ANNOUNCE.2.1: -------------------------------------------------------------------------------- 1 | GNUstep Objective-C Runtime 2.1 2 | ================================= 3 | 4 | This is the first update to the second major release of the GNUstep Objective-C 5 | runtime (a.k.a. libobjc2). This runtime was designed to support the features 6 | of modern dialects of Objective-C for use with GNUstep and other Objective-C 7 | programs. 8 | 9 | *NOTE:* This is the first release to use submodules. If you are downloading 10 | the sources from git, please make sure that you do a recursive clone. If you 11 | forget, the build system will give you instructions to correct this. 12 | Tarballs from GitHub do not include submodules, so if you are downloading the 13 | tarball then you will need to download the submodule separately. 14 | 15 | 16 | Highlights of this release include: 17 | 18 | - Numerous improvements to the Objective-C++ exception interoperation code. 19 | The runtime now dynamically detects whether the libcxxrt or libsupc++ variant 20 | of the Itanium C++ Exception ABI is being used 21 | 22 | - Sending a message to `super` where the corresponding method did not exist was 23 | silently ignored in previous versions of the runtime. This now correctly 24 | invokes the forwarding hooks and so (with an implementation of the Foundation 25 | framework, such as GNUstep Base or WinObjC) will trigger an exception or 26 | invoke `forwardInvocation:`. 27 | 28 | - The checks for overloaded memory management methods were incorrect, causing 29 | some classes to be incorrectly opted into ARC fast paths. These checks are 30 | now correct. 31 | 32 | - Several memory management bugs in corner cases of weak reference management 33 | were fixed. 34 | 35 | - The ARM assembly implementation of `objc_msgSend` now correctly restores the 36 | stack after calling a forwarding implementation. This bug caused stack 37 | corruption and usually crashing on ARM. 38 | 39 | - The ARC code has been rewritten as C++, using a well-tested third-party 40 | Robin-Hood hash table to store weak references, replacing the home-grown 41 | version. This improves performance and reduces the likelihood of bugs 42 | arising from the hash table implementation. 43 | 44 | - Control Flow Guard (CGF) checks were added on Windows on x86 (32- and 45 | 64-bit). If Objective-C code is compiled with CFG enabled then 46 | `objc_msgSend` will crash if it attempts to jump to an address that is not a 47 | valid function entry point. 48 | 49 | - The function signatures in the blocks headers were updated for compatibility 50 | with recent macOS releases. 51 | 52 | - Support for the C11 _Atomic type qualifier in property metadata was added. 53 | 54 | You may obtain the code for this release from git and use the 2.1 branch: 55 | 56 | https://github.com/gnustep/libobjc2.git 57 | 58 | Alternatively, a tarball is available from: 59 | 60 | https://github.com/gnustep/libobjc2/archive/v2.1.zip 61 | https://github.com/gnustep/libobjc2/archive/v2.1.tar.gz 62 | 63 | The submodule is available from: 64 | 65 | https://github.com/Tessil/robin-map/archive/757de82.zip 66 | https://github.com/Tessil/robin-map/archive/757de82.tar.gz 67 | 68 | This will extract as robin-map-757de829927489bee55ab02147484850c687b620. 69 | You must move the contents of that directory into third_party/robin_map in the 70 | libobjc2 tree. 71 | 72 | 73 | The runtime library is responsible for implementing the core features of the 74 | object model, as well as exposing introspection features to the user. The 75 | GNUstep runtime implements a superset of Apple's Objective-C Runtime APIs. 76 | 77 | If you come across any problems, please file them in the issue tracker: 78 | 79 | https://github.com/gnustep/libobjc2/issues 80 | -------------------------------------------------------------------------------- /Block.h: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /Block_private.h: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /CMake/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | project(test_cxx_runtime) 3 | 4 | add_executable(test_cxx_runtime typeinfo_test.cc) 5 | add_executable(test_cxx_stdlib typeinfo_test.cc) 6 | if (CXX_RUNTIME) 7 | if (CXX_RUNTIME MATCHES ".*libc\\+\\+abi.*") 8 | find_library(M_LIBRARY m) 9 | if (M_LIBRARY) 10 | target_link_libraries(test_cxx_runtime ${M_LIBRARY}) 11 | endif() 12 | endif() 13 | set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "") 14 | target_link_libraries(test_cxx_runtime ${CXX_RUNTIME}) 15 | set_target_properties(test_cxx_runtime PROPERTIES 16 | LINKER_LANGUAGE C) 17 | endif() 18 | -------------------------------------------------------------------------------- /CMake/typeinfo_test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace __cxxabiv1 4 | { 5 | struct __class_type_info; 6 | } 7 | 8 | using __cxxabiv1::__class_type_info; 9 | 10 | namespace std 11 | { 12 | /** 13 | * std::type_info defined with the GCC ABI. This may not be exposed in 14 | * public headers, but is required for correctly implementing the unified 15 | * exception model. 16 | */ 17 | class type_info 18 | { 19 | public: 20 | virtual ~type_info(); 21 | bool operator==(const type_info &) const; 22 | bool operator!=(const type_info &) const; 23 | bool before(const type_info &) const; 24 | private: 25 | type_info(const type_info& rhs); 26 | type_info& operator= (const type_info& rhs); 27 | const char *__type_name; 28 | protected: 29 | type_info(const char *name): __type_name(name) { } 30 | public: 31 | const char* name() const { return __type_name; } 32 | virtual bool __is_pointer_p() const; 33 | virtual bool __is_function_p() const; 34 | virtual bool __do_catch(const type_info *thrown_type, 35 | void **thrown_object, 36 | unsigned outer) const; 37 | virtual bool __do_upcast( 38 | const __class_type_info *target, 39 | void **thrown_object) const; 40 | }; 41 | } 42 | 43 | class type_info2 : public std::type_info 44 | { 45 | public: 46 | type_info2() : type_info("foo") {} 47 | virtual bool __is_pointer_p() const; 48 | virtual bool __is_function_p() const { return true; } 49 | virtual bool __do_catch(const type_info *thrown_type, 50 | void **thrown_object, 51 | unsigned outer) const { return true; } 52 | virtual bool __do_upcast( 53 | const __class_type_info *target, 54 | void **thrown_object) const { return true; }; 55 | }; 56 | bool type_info2::__is_pointer_p() const { return true; } 57 | 58 | int main() 59 | { 60 | type_info2 s; 61 | return s.__is_pointer_p(); 62 | } 63 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 David Chisnall 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | 21 | -------------------------------------------------------------------------------- /Config.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | include ( "${CMAKE_CURRENT_LIST_DIR}/libobjcTargets.cmake" ) 4 | -------------------------------------------------------------------------------- /NSBlocks.m: -------------------------------------------------------------------------------- 1 | #include "objc/runtime.h" 2 | #include "class.h" 3 | #include "loader.h" 4 | #include "lock.h" 5 | #include "objc/blocks_runtime.h" 6 | #include "dtable.h" 7 | #include 8 | 9 | #ifdef EMBEDDED_BLOCKS_RUNTIME 10 | #define BLOCK_STORAGE OBJC_PUBLIC 11 | #else 12 | #define BLOCK_STORAGE extern 13 | #endif 14 | 15 | BLOCK_STORAGE struct objc_class _NSConcreteGlobalBlock; 16 | BLOCK_STORAGE struct objc_class _NSConcreteStackBlock; 17 | BLOCK_STORAGE struct objc_class _NSConcreteMallocBlock; 18 | BLOCK_STORAGE struct objc_class _NSConcreteAutoBlock; 19 | BLOCK_STORAGE struct objc_class _NSConcreteFinalizingBlock; 20 | 21 | static struct objc_class _NSConcreteGlobalBlockMeta; 22 | static struct objc_class _NSConcreteStackBlockMeta; 23 | static struct objc_class _NSConcreteMallocBlockMeta; 24 | static struct objc_class _NSConcreteAutoBlockMeta; 25 | static struct objc_class _NSConcreteFinalizingBlockMeta; 26 | 27 | static struct objc_class _NSBlock; 28 | static struct objc_class _NSBlockMeta; 29 | 30 | static void createNSBlockSubclass(Class superclass, Class newClass, 31 | Class metaClass, char *name) 32 | { 33 | // Initialize the metaclass 34 | //metaClass->class_pointer = superclass->class_pointer; 35 | //metaClass->super_class = superclass->class_pointer; 36 | metaClass->info = objc_class_flag_meta; 37 | metaClass->dtable = uninstalled_dtable; 38 | 39 | // Set up the new class 40 | newClass->isa = metaClass; 41 | newClass->super_class = superclass; 42 | newClass->name = name; 43 | newClass->dtable = uninstalled_dtable; 44 | newClass->info = objc_class_flag_is_block; 45 | 46 | LOCK_RUNTIME_FOR_SCOPE(); 47 | objc_load_class(newClass); 48 | 49 | } 50 | 51 | #define NEW_CLASS(super, sub) \ 52 | createNSBlockSubclass(super, &sub, &sub ## Meta, #sub) 53 | 54 | OBJC_PUBLIC 55 | BOOL objc_create_block_classes_as_subclasses_of(Class super) 56 | { 57 | if (_NSBlock.super_class != NULL) { return NO; } 58 | 59 | NEW_CLASS(super, _NSBlock); 60 | NEW_CLASS(&_NSBlock, _NSConcreteStackBlock); 61 | NEW_CLASS(&_NSBlock, _NSConcreteGlobalBlock); 62 | NEW_CLASS(&_NSBlock, _NSConcreteMallocBlock); 63 | NEW_CLASS(&_NSBlock, _NSConcreteAutoBlock); 64 | NEW_CLASS(&_NSBlock, _NSConcreteFinalizingBlock); 65 | // Global blocks never need refcount manipulation. 66 | objc_set_class_flag(&_NSConcreteGlobalBlock, 67 | objc_class_flag_permanent_instances); 68 | return YES; 69 | } 70 | 71 | PRIVATE void init_early_blocks(void) 72 | { 73 | if (_NSBlock.super_class != NULL) { return; } 74 | _NSConcreteStackBlock.info = objc_class_flag_is_block; 75 | _NSConcreteGlobalBlock.info = objc_class_flag_is_block | objc_class_flag_permanent_instances; 76 | _NSConcreteMallocBlock.info = objc_class_flag_is_block; 77 | _NSConcreteAutoBlock.info = objc_class_flag_is_block; 78 | _NSConcreteFinalizingBlock.info = objc_class_flag_is_block; 79 | } -------------------------------------------------------------------------------- /README.windows: -------------------------------------------------------------------------------- 1 | Building on Windows 2 | =================== 3 | 4 | The runtime can build on Windows with Ninja: 5 | 6 | ``` 7 | > mkdir build 8 | > cd build 9 | > cmake .. -G Ninja -DCMAKE_C_COMPILER=path/to/clang.exe -DCMAKE_CXX_COMPILER=path/to/clang.exe 10 | > ninja 11 | ``` 12 | -------------------------------------------------------------------------------- /Test/ARCTest_arc.m: -------------------------------------------------------------------------------- 1 | #import "Test.h" 2 | 3 | // Checks using non-portable APIs 4 | #ifdef GNUSTEP_RUNTIME 5 | void check_retain_count(id obj, size_t rc) 6 | { 7 | assert(object_getRetainCount_np(obj) == rc); 8 | } 9 | void check_autorelease_count(id obj, size_t rc) 10 | { 11 | assert(objc_arc_autorelease_count_for_object_np(obj) == rc); 12 | } 13 | #else 14 | void check_retain_count(id obj, size_t rc) 15 | { 16 | } 17 | void check_autorelease_count(id obj, size_t rc) 18 | { 19 | } 20 | #endif 21 | 22 | id __weak var; 23 | 24 | @interface ARC : Test @end 25 | @implementation ARC 26 | - (id __autoreleasing)loadWeakAutoreleasing 27 | { 28 | return var; 29 | } 30 | - (id)loadWeak 31 | { 32 | return var; 33 | } 34 | - (void)setWeakFromWeak: (id __weak)anObject 35 | { 36 | var = anObject; 37 | anObject = nil; 38 | } 39 | - (void)setWeak: (id)anObject 40 | { 41 | var = anObject; 42 | } 43 | @end 44 | 45 | @interface CheckDealloc : Test 46 | @end 47 | @implementation CheckDealloc 48 | { 49 | BOOL *flag; 50 | } 51 | - (id)initWithFlag: (BOOL*)aFlag 52 | { 53 | flag = aFlag; 54 | *flag = NO; 55 | return self; 56 | } 57 | - (void)dealloc 58 | { 59 | *flag = YES; 60 | } 61 | @end 62 | 63 | static __weak id weakRef; 64 | 65 | @interface CheckDeallocWeakRef : Test 66 | @end 67 | @implementation CheckDeallocWeakRef 68 | - (void)dealloc 69 | { 70 | weakRef = self; 71 | } 72 | @end 73 | 74 | 75 | int main(void) 76 | { 77 | ARC *obj = [ARC new]; 78 | BOOL f1; 79 | BOOL f2; 80 | // Check that storing weak references works. 81 | { 82 | id o1 = [[CheckDealloc new] initWithFlag: &f1]; 83 | id o2 = [[CheckDealloc new] initWithFlag: &f2]; 84 | [obj setWeak: o1]; 85 | assert([obj loadWeak] == o1); 86 | [obj setWeakFromWeak: o2]; 87 | assert([obj loadWeak] == o2); 88 | @autoreleasepool 89 | { 90 | id __autoreleasing o2a = [obj loadWeakAutoreleasing]; 91 | assert(o2a == o2); 92 | } 93 | } 94 | assert(f1); 95 | assert(f2); 96 | assert([obj loadWeak] == nil); 97 | @autoreleasepool 98 | { 99 | id __autoreleasing o1a; 100 | { 101 | id o1 = [[CheckDealloc new] initWithFlag: &f1]; 102 | assert(!f1); 103 | [obj setWeak: o1]; 104 | assert([obj loadWeak] == o1); 105 | o1a = [obj loadWeakAutoreleasing]; 106 | assert(o1a == o1); 107 | check_autorelease_count(o1a, 1); 108 | check_retain_count(o1a, 1); 109 | } 110 | assert(o1a == [obj loadWeak]); 111 | } 112 | assert(f1); 113 | assert([obj loadWeak] == nil); 114 | // Try to trigger an objc_moveWeak call 115 | { 116 | id o1 = [Test new]; 117 | { 118 | id __weak x = o1; 119 | var = x; 120 | } 121 | } 122 | assert([obj loadWeak] == nil); 123 | // Now check what happens with a constant string in a weak variable. 124 | { 125 | id x = @"foo"; 126 | [obj setWeak: x]; 127 | } 128 | assert([obj loadWeak] != nil); 129 | // Check setting weak references during dealloc 130 | { 131 | [CheckDeallocWeakRef new]; 132 | } 133 | assert(weakRef == nil); 134 | return 0; 135 | } 136 | -------------------------------------------------------------------------------- /Test/AllocatePair.m: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | #include 3 | 4 | // Regression test for a bug where allocating a class as a subclass of an 5 | // unresolved class failed. 6 | 7 | static int loaded; 8 | 9 | static void load(Class self, SEL _cmd) 10 | { 11 | loaded++; 12 | } 13 | 14 | int main() 15 | { 16 | Class a, b, c, d, e; 17 | 18 | assert(class_getInstanceSize(objc_allocateClassPair(Nil, "Empty", 0)) == sizeof(Class)); 19 | a = objc_allocateClassPair([Test class], "A", 0); 20 | objc_registerClassPair(a); 21 | 22 | b = objc_allocateClassPair(a, "B", 0); 23 | class_addMethod(object_getClass(b), @selector(load), (IMP)load, "@:"); 24 | 25 | class_addIvar(b, "anIvar", 4, 2, "i"); 26 | objc_registerClassPair(b); 27 | 28 | Ivar iv = class_getInstanceVariable(b, "anIvar"); 29 | size_t superSize = class_getInstanceSize([Test class]); 30 | assert(ivar_getOffset(iv) == superSize); 31 | 32 | class_getSuperclass(b); 33 | 34 | 35 | c = objc_allocateClassPair(b, "C", 0); 36 | objc_registerClassPair(c); 37 | d = objc_allocateClassPair(c, "D", 0); 38 | objc_registerClassPair(d); 39 | e = objc_allocateClassPair(d, "E", 0); 40 | objc_registerClassPair(e); 41 | assert(loaded == 0); 42 | assert(objc_getClass("C") == c); 43 | assert(objc_getClass("D") == d); 44 | assert(objc_getClass("E") == e); 45 | objc_disposeClassPair(e); 46 | assert(objc_getClass("E") == nil); 47 | 48 | return 0; 49 | } 50 | 51 | 52 | -------------------------------------------------------------------------------- /Test/AssociatedObject.m: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | #include 3 | #include 4 | 5 | BOOL deallocCalled = NO; 6 | static const char* objc_setAssociatedObjectKey = "objc_setAssociatedObjectKey"; 7 | 8 | @interface Associated : Test 9 | @end 10 | 11 | @implementation Associated 12 | -(void) dealloc 13 | { 14 | deallocCalled = YES; 15 | [super dealloc]; 16 | } 17 | @end 18 | 19 | int main(void) 20 | { 21 | @autoreleasepool { 22 | Associated *object = [Associated new]; 23 | Test *holder = [[Test new] autorelease]; 24 | objc_setAssociatedObject(holder, &objc_setAssociatedObjectKey, object, OBJC_ASSOCIATION_RETAIN); 25 | [object release]; 26 | assert(!deallocCalled); 27 | } 28 | // dealloc should be called when holder is released during pool drain 29 | assert(deallocCalled); 30 | 31 | deallocCalled = NO; 32 | 33 | Associated *object = [Associated new]; 34 | Test *holder = [Test new]; 35 | objc_setAssociatedObject(holder, &objc_setAssociatedObjectKey, object, OBJC_ASSOCIATION_RETAIN); 36 | [object release]; // commuted into associated object storage 37 | objc_setAssociatedObject(holder, &objc_setAssociatedObjectKey, nil, OBJC_ASSOCIATION_ASSIGN); 38 | [holder release]; 39 | 40 | assert(deallocCalled); 41 | 42 | object = [Associated new]; 43 | holder = [Test new]; 44 | size_t rc = object_getRetainCount_np(object); 45 | for (uintptr_t i = 1; i <= 20; ++i) 46 | { 47 | objc_setAssociatedObject(holder, (void*)i, object, OBJC_ASSOCIATION_RETAIN); 48 | assert(rc + i == object_getRetainCount_np(object)); 49 | } 50 | int lost = 0; 51 | for (uintptr_t i = 1; i <= 20; ++i) 52 | { 53 | if (object != objc_getAssociatedObject(holder, (const void*)i)) 54 | { 55 | fprintf(stderr, "lost object %" PRIuPTR "\n", i); 56 | ++lost; 57 | } 58 | assert(rc + 20 + i == object_getRetainCount_np(object)); 59 | } 60 | [holder release]; 61 | [object release]; 62 | assert(0 == lost); 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /Test/AssociatedObject2.m: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | 3 | @interface MLTestClass : Test { 4 | @public 5 | } 6 | - (void)someF; 7 | @end 8 | 9 | @implementation MLTestClass 10 | - (void)someF 11 | { 12 | } 13 | 14 | @end 15 | 16 | static void ff(id obj, SEL _cmd) 17 | { 18 | } 19 | 20 | 21 | int main() 22 | { 23 | static char static_char; 24 | MLTestClass * tc; 25 | tc = [MLTestClass new]; 26 | objc_setAssociatedObject(tc, &static_char, (id)1223, OBJC_ASSOCIATION_ASSIGN); 27 | [tc release]; 28 | tc = [MLTestClass new]; 29 | objc_setAssociatedObject(tc, &static_char, (id)1223, OBJC_ASSOCIATION_ASSIGN); 30 | SEL some_sel = sel_registerName(".some_sel"); 31 | const char *types = "v@:"; 32 | class_addMethod(object_getClass(tc), some_sel, 33 | (IMP)ff, types); 34 | int j = (int)objc_getAssociatedObject(tc, &static_char); 35 | assert(j == 1223); 36 | [tc release]; 37 | } 38 | -------------------------------------------------------------------------------- /Test/BlockImpTest.m: -------------------------------------------------------------------------------- 1 | #include "../objc/runtime.h" 2 | #include "../objc/blocks_runtime.h" 3 | #include 4 | #include 5 | #include 6 | 7 | struct big 8 | { 9 | int a, b, c, d, e; 10 | }; 11 | 12 | #ifdef __has_attribute 13 | #if __has_attribute(objc_root_class) 14 | __attribute__((objc_root_class)) 15 | #endif 16 | #endif 17 | @interface Foo @end 18 | @implementation Foo @end 19 | @interface Foo (Dynamic) 20 | +(int)count: (int)i; 21 | +(struct big)sret; 22 | @end 23 | 24 | 25 | int main(void) 26 | { 27 | __block Class cls = objc_getClass("Foo"); 28 | __block int b = 0; 29 | void* blk = ^(id self, int a) { 30 | assert(self == cls); 31 | b += a; 32 | return b; }; 33 | blk = Block_copy(blk); 34 | IMP imp = imp_implementationWithBlock(blk); 35 | char *type = block_copyIMPTypeEncoding_np(blk); 36 | assert(NULL != type); 37 | class_addMethod((objc_getMetaClass("Foo")), @selector(count:), imp, type); 38 | assert(2 == ((int(*)(id,SEL,int))imp)(cls, @selector(count:), 2)); 39 | free(type); 40 | assert(4 == [Foo count: 2]); 41 | assert(6 == [Foo count: 2]); 42 | assert(imp_getBlock(imp) == (blk)); 43 | IMP imp2 = imp_implementationWithBlock(blk); 44 | assert(imp != imp2); 45 | imp_removeBlock(imp); 46 | assert(imp_getBlock(imp) != (blk)); 47 | 48 | blk = ^(id self) { 49 | assert(self == cls); 50 | struct big b = {1, 2, 3, 4, 5}; 51 | return b; 52 | }; 53 | imp = imp_implementationWithBlock(blk); 54 | assert(imp && "Can't make sret IMP"); 55 | type = block_copyIMPTypeEncoding_np(blk); 56 | assert(NULL != type); 57 | class_addMethod((objc_getMetaClass("Foo")), @selector(sret), imp, type); 58 | free(type); 59 | struct big s = [Foo sret]; 60 | assert(s.a == 1); 61 | assert(s.b == 2); 62 | assert(s.c == 3); 63 | assert(s.d == 4); 64 | assert(s.e == 5); 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /Test/BlockTest_arc.m: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int foo() { 4 | __block id x; 5 | void (^hello)(void) = ^(void) { 6 | printf("hello is running, %p\n", x); 7 | }; 8 | printf("1\n"); 9 | hello(); 10 | printf("2\n"); 11 | hello = 0; // Here ARC is releasing the block, that's why we don't see '3' printed. 12 | printf("3\n"); 13 | return 0; 14 | } 15 | int main() { 16 | return foo(); 17 | } 18 | -------------------------------------------------------------------------------- /Test/BoxedForeignException.m: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include "../unwind.h" 3 | #include "Test.h" 4 | #include "../objc/hooks.h" 5 | #include 6 | 7 | 8 | struct foreign_exception 9 | { 10 | struct _Unwind_Exception header; 11 | int x; 12 | }; 13 | 14 | BOOL finally_called = NO; 15 | 16 | 17 | int throw(void) 18 | { 19 | struct foreign_exception *foreign_exception = calloc(sizeof(struct foreign_exception), 1); 20 | foreign_exception->header.exception_class = 42; 21 | foreign_exception->x = 12; 22 | _Unwind_RaiseException(&foreign_exception->header); 23 | assert(0); 24 | } 25 | 26 | void finally(void) 27 | { 28 | @try 29 | { 30 | throw(); 31 | } 32 | @finally 33 | { 34 | finally_called = YES; 35 | } 36 | finally_called = NO; 37 | } 38 | @interface BoxedException : Test 39 | { 40 | struct foreign_exception *exception; 41 | } 42 | - (int)value; 43 | @end 44 | @implementation BoxedException 45 | + (id) exceptionWithForeignException: (struct _Unwind_Exception*)ex 46 | { 47 | BoxedException *b = [BoxedException new]; 48 | b->exception = (struct foreign_exception*)ex; 49 | return b; 50 | } 51 | - (void)dealloc 52 | { 53 | free(exception); 54 | [super dealloc]; 55 | } 56 | - (int)value 57 | { 58 | if (exception) 59 | { 60 | return exception->x; 61 | } 62 | return -1; 63 | } 64 | - (void)rethrow 65 | { 66 | struct _Unwind_Exception *ex = &exception->header; 67 | exception = 0; 68 | [self dealloc]; 69 | _Unwind_Resume_or_Rethrow(ex); 70 | abort(); 71 | } 72 | @end 73 | 74 | 75 | Class boxer(int64_t class) 76 | { 77 | assert(class == 42); 78 | return [BoxedException class]; 79 | } 80 | 81 | int main(void) 82 | { 83 | _objc_class_for_boxing_foreign_exception = boxer; 84 | BOOL catchall = NO; 85 | BOOL catchboxed = NO; 86 | @try 87 | { 88 | finally(); 89 | } 90 | @catch (BoxedException *x) 91 | { 92 | assert(x != nil); 93 | assert([x value] == 12); 94 | [x dealloc]; 95 | catchboxed = YES; 96 | } 97 | @catch(...) 98 | { 99 | catchall = YES; 100 | } 101 | assert(finally_called == YES); 102 | assert(catchall == NO); 103 | assert(catchboxed == YES); 104 | return 0; 105 | } 106 | -------------------------------------------------------------------------------- /Test/CXXException.cc: -------------------------------------------------------------------------------- 1 | 2 | extern "C" void throw_int() 3 | { 4 | throw 12; 5 | } 6 | 7 | extern "C" void throw_id(); 8 | 9 | 10 | extern "C" int catchall() 11 | { 12 | try 13 | { 14 | throw_id(); 15 | } 16 | catch(...) 17 | { 18 | throw; 19 | } 20 | __builtin_trap(); 21 | } 22 | -------------------------------------------------------------------------------- /Test/CXXException.m: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | #include "../unwind.h" 3 | 4 | #if __cplusplus 5 | #error This is not an ObjC++ test! 6 | #endif 7 | 8 | struct 9 | { 10 | struct _Unwind_Exception header; 11 | id x; 12 | } foreign_exception; 13 | 14 | BOOL finally_called = NO; 15 | 16 | id e1; 17 | void throw_id(void) 18 | { 19 | @throw e1; 20 | } 21 | 22 | void throw_int(void); 23 | int catchall(void); 24 | 25 | 26 | void finally(void) 27 | { 28 | @try 29 | { 30 | throw_int(); 31 | } 32 | @finally 33 | { 34 | finally_called = YES; 35 | } 36 | finally_called = NO; 37 | } 38 | 39 | 40 | int main(void) 41 | { 42 | BOOL catchall_entered = NO; 43 | BOOL catchid = YES; 44 | e1 = [Test new]; 45 | @try 46 | { 47 | finally(); 48 | } 49 | @catch (id x) 50 | { 51 | assert(0); 52 | } 53 | @catch(...) 54 | { 55 | catchall_entered = YES; 56 | } 57 | assert(finally_called == YES); 58 | assert(catchall_entered == YES); 59 | @try 60 | { 61 | catchall(); 62 | } 63 | @catch (id x) 64 | { 65 | assert(x == e1); 66 | } 67 | assert(catchid == YES); 68 | [e1 dealloc]; 69 | return 0; 70 | } 71 | -------------------------------------------------------------------------------- /Test/Category.m: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | #include "../objc/runtime.h" 3 | 4 | #pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation" 5 | @interface Foo : Test 6 | + (int)replaced; 7 | @end 8 | @implementation Foo 9 | + (int)replaced 10 | { 11 | return 1; 12 | } 13 | @end 14 | 15 | @implementation Foo (bar) 16 | + (int)replaced 17 | { 18 | return 2; 19 | } 20 | @end 21 | 22 | int main (void) 23 | { 24 | assert([Foo replaced] == 2); 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /Test/ConstantString.m: -------------------------------------------------------------------------------- 1 | #import "Test.h" 2 | #include 3 | 4 | @implementation NSConstantString (Test) 5 | - (unsigned int)length 6 | { 7 | return length; 8 | } 9 | - (const char*)cString 10 | { 11 | return str; 12 | } 13 | @end 14 | 15 | 16 | int main(void) 17 | { 18 | assert([@"1234567890" length] == 10); 19 | assert(strcmp([@"123456789" cString], "123456789") == 0); 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /Test/DirectMethods.m: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | 3 | #if !__has_attribute(objc_direct) 4 | int main() 5 | { 6 | return 77; 7 | } 8 | #else 9 | 10 | static BOOL initializeCalled; 11 | static BOOL directMethodCalled; 12 | 13 | @interface HasDirect : Test 14 | + (void)clsDirect __attribute__((objc_direct)); 15 | - (int)instanceDirect __attribute__((objc_direct)); 16 | @end 17 | @implementation HasDirect 18 | + (void)initialize 19 | { 20 | initializeCalled = YES; 21 | } 22 | + (void)clsDirect 23 | { 24 | directMethodCalled = YES; 25 | } 26 | - (int)instanceDirect 27 | { 28 | return 42; 29 | } 30 | @end 31 | 32 | int main(void) 33 | { 34 | [HasDirect clsDirect]; 35 | assert(directMethodCalled); 36 | assert(initializeCalled); 37 | HasDirect *obj = [HasDirect new]; 38 | assert([obj instanceDirect] == 42); 39 | obj = nil; 40 | assert([obj instanceDirect] == 0); 41 | return 0; 42 | } 43 | 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /Test/ExceptionTest.m: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | 3 | #if __cplusplus 4 | #error This is not an ObjC++ test! 5 | #endif 6 | 7 | BOOL finallyEntered = NO; 8 | BOOL cleanupRun = NO; 9 | BOOL idRethrown = NO; 10 | BOOL catchallRethrown = NO; 11 | BOOL testCaught = NO; 12 | BOOL wrongMatch = NO; 13 | 14 | @interface NSString : Test @end 15 | void runCleanup(void *x) 16 | { 17 | assert(cleanupRun == NO); 18 | cleanupRun = YES; 19 | } 20 | 21 | int throw(void) 22 | { 23 | @throw [Test new]; 24 | } 25 | 26 | int finally(void) 27 | { 28 | __attribute__((cleanup(runCleanup))) 29 | int x; 30 | (void)x; 31 | @try { throw(); } 32 | @finally { finallyEntered = YES; } 33 | return 0; 34 | } 35 | int rethrow_id(void) 36 | { 37 | @try { finally(); } 38 | @catch(id x) 39 | { 40 | assert(object_getClass(x) == [Test class]); 41 | idRethrown = YES; 42 | @throw; 43 | } 44 | return 0; 45 | } 46 | int rethrow_test(void) 47 | { 48 | @try { rethrow_id(); } 49 | @catch (Test *t) 50 | { 51 | testCaught = YES; 52 | @throw; 53 | } 54 | @catch (id x) 55 | { 56 | assert(0 && "should not be reached!"); 57 | } 58 | @catch (...) 59 | { 60 | assert(0 && "should not be reached!"); 61 | } 62 | } 63 | int rethrow_catchall(void) 64 | { 65 | @try { rethrow_test(); } 66 | @catch(...) 67 | { 68 | assert(testCaught); 69 | catchallRethrown = YES; 70 | @throw; 71 | } 72 | return 0; 73 | } 74 | int not_matched_catch(void) 75 | { 76 | @try { rethrow_catchall(); } 77 | @catch(NSString *s) 78 | { 79 | wrongMatch = YES; 80 | } 81 | return 0; 82 | } 83 | 84 | int main(void) 85 | { 86 | @try 87 | { 88 | rethrow_catchall(); 89 | } 90 | @catch (id x) 91 | { 92 | assert(finallyEntered == YES); 93 | assert(cleanupRun == YES); 94 | assert(idRethrown == YES); 95 | assert(catchallRethrown == YES); 96 | assert(wrongMatch == NO); 97 | assert(object_getClass(x) == [Test class]); 98 | [x dealloc]; 99 | } 100 | return 0; 101 | } 102 | -------------------------------------------------------------------------------- /Test/FastARC.m: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | #include 3 | 4 | static BOOL called; 5 | 6 | @interface AllUnsafe : Test @end 7 | @implementation AllUnsafe 8 | - (id)retain 9 | { 10 | return self; 11 | } 12 | - (void)release {} 13 | - (id)autorelease 14 | { 15 | return self; 16 | } 17 | @end 18 | 19 | @interface Retain : AllUnsafe @end 20 | @implementation Retain 21 | - (id)retain 22 | { 23 | called = YES; 24 | return self; 25 | } 26 | @end 27 | 28 | @interface RetainSafe : AllUnsafe @end 29 | @implementation RetainSafe 30 | - (id)retain 31 | { 32 | return self; 33 | } 34 | - (void)_ARCCompliantRetainRelease {} 35 | @end 36 | 37 | @interface Release : AllUnsafe @end 38 | @implementation Release 39 | - (void)release 40 | { 41 | called = YES; 42 | } 43 | @end 44 | 45 | @interface ReleaseSafe : AllUnsafe @end 46 | @implementation ReleaseSafe 47 | - (void)release 48 | { 49 | } 50 | - (void)_ARCCompliantRetainRelease {} 51 | @end 52 | 53 | @interface Autorelease : AllUnsafe @end 54 | @implementation Autorelease 55 | - (id)autorelease 56 | { 57 | called = YES; 58 | return self; 59 | } 60 | @end 61 | 62 | @interface AutoreleaseSafe : AllUnsafe @end 63 | @implementation AutoreleaseSafe 64 | - (id)autorelease 65 | { 66 | return self; 67 | } 68 | - (void)_ARCCompliantRetainRelease {} 69 | @end 70 | 71 | void check(id obj, BOOL expected) 72 | { 73 | fprintf(stderr, "Checking %s\n", class_getName(object_getClass(obj))); 74 | } 75 | 76 | int main() 77 | { 78 | called = NO; 79 | objc_retain([Retain new]); 80 | assert(called == YES); 81 | 82 | called = NO; 83 | objc_retain([RetainSafe new]); 84 | assert(called == NO); 85 | 86 | called = NO; 87 | objc_release([Release new]); 88 | assert(called == YES); 89 | 90 | called = NO; 91 | objc_release([ReleaseSafe new]); 92 | assert(called == NO); 93 | 94 | called = NO; 95 | objc_autorelease([Autorelease new]); 96 | assert(called == YES); 97 | 98 | called = NO; 99 | objc_autorelease([AutoreleaseSafe new]); 100 | assert(called == NO); 101 | 102 | return 0; 103 | } 104 | 105 | -------------------------------------------------------------------------------- /Test/FastARCPool.m: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | 3 | #define POOL_SIZE (4096 / sizeof(void*)) 4 | 5 | static BOOL called; 6 | 7 | @interface Canary : Test 8 | @end 9 | @implementation Canary 10 | - (void)dealloc 11 | { 12 | called = YES; 13 | [super dealloc]; 14 | } 15 | @end 16 | 17 | @interface Creator : Test 18 | @end 19 | @implementation Creator 20 | - (void)dealloc 21 | { 22 | // Add a new page of autorelease references to see if we can still release 23 | // the reference on the canary object. 24 | for (int i = 0; i < POOL_SIZE; i++) 25 | [[Test new] autorelease]; 26 | [super dealloc]; 27 | } 28 | @end 29 | 30 | int main() 31 | { 32 | called = NO; 33 | @autoreleasepool 34 | { 35 | [[Canary new] autorelease]; 36 | [[Creator new] autorelease]; 37 | } 38 | assert(called == YES); 39 | 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /Test/FastPathAlloc.m: -------------------------------------------------------------------------------- 1 | #if __clang_major__ < 18 || (__clang_major__ == 18 && __clang_minor__ < 1) 2 | // Skip this test if clang is too old to support it. 3 | int main(void) 4 | { 5 | return 77; 6 | } 7 | #else 8 | #include "Test.h" 9 | #include 10 | 11 | static BOOL called; 12 | 13 | typedef struct _NSZone NSZone; 14 | 15 | @interface ShouldAlloc : Test @end 16 | @interface ShouldAllocWithZone : Test @end 17 | @interface ShouldInit : Test @end 18 | @interface ShouldInit2 : Test @end 19 | 20 | @interface NoAlloc : Test @end 21 | @interface NoInit : Test @end 22 | @interface NoInit2 : NoInit @end 23 | 24 | @interface ShouldInitSubclassed : NoInit @end 25 | 26 | @implementation ShouldAlloc 27 | + (instancetype)alloc 28 | { 29 | called = YES; 30 | fprintf(stderr, "[%s %s] called\n", class_getName(object_getClass(self)), sel_getName(_cmd)); 31 | return [super alloc]; 32 | } 33 | @end 34 | @implementation ShouldAllocWithZone 35 | + (instancetype)allocWithZone: (NSZone*)aZone 36 | { 37 | called = YES; 38 | fprintf(stderr, "[%s %s] called\n", class_getName(object_getClass(self)), sel_getName(_cmd)); 39 | return [super alloc]; 40 | } 41 | @end 42 | @implementation ShouldInit 43 | - (instancetype)init 44 | { 45 | called = YES; 46 | fprintf(stderr, "[%s %s] called\n", class_getName(object_getClass(self)), sel_getName(_cmd)); 47 | return self; 48 | } 49 | @end 50 | @implementation ShouldInit2 51 | + (instancetype)alloc 52 | { 53 | fprintf(stderr, "[%s %s] called\n", class_getName(object_getClass(self)), sel_getName(_cmd)); 54 | return [super alloc]; 55 | } 56 | - (instancetype)init 57 | { 58 | called = YES; 59 | fprintf(stderr, "[%s %s] called\n", class_getName(object_getClass(self)), sel_getName(_cmd)); 60 | return self; 61 | } 62 | @end 63 | 64 | @implementation NoAlloc 65 | + (void)_TrivialAllocInit{} 66 | + (instancetype)alloc 67 | { 68 | called = YES; 69 | fprintf(stderr, "[%s %s] called\n", class_getName(object_getClass(self)), sel_getName(_cmd)); 70 | return [super alloc]; 71 | } 72 | + (instancetype)allocWithZone: (NSZone*)aZone 73 | { 74 | called = YES; 75 | fprintf(stderr, "[%s %s] called\n", class_getName(object_getClass(self)), sel_getName(_cmd)); 76 | return [super alloc]; 77 | } 78 | @end 79 | @implementation NoInit 80 | + (void)_TrivialAllocInit{} 81 | - (instancetype)init 82 | { 83 | called = YES; 84 | fprintf(stderr, "[%s %s] called\n", class_getName(object_getClass(self)), sel_getName(_cmd)); 85 | return self; 86 | } 87 | @end 88 | @implementation NoInit2 89 | + (instancetype)alloc 90 | { 91 | fprintf(stderr, "[%s %s] called\n", class_getName(object_getClass(self)), sel_getName(_cmd)); 92 | return [super alloc]; 93 | } 94 | @end 95 | 96 | @implementation ShouldInitSubclassed 97 | + (instancetype) alloc 98 | { 99 | return [ShouldInit alloc]; 100 | } 101 | @end 102 | 103 | Class getClassNamed(char *name) 104 | { 105 | return nil; 106 | } 107 | 108 | int main(void) 109 | { 110 | called = NO; 111 | [ShouldAlloc alloc]; 112 | assert(called); 113 | 114 | [ShouldAllocWithZone allocWithZone: NULL]; 115 | assert(called); 116 | called = NO; 117 | 118 | called = NO; 119 | [[ShouldInit alloc] init]; 120 | assert(called); 121 | 122 | called = NO; 123 | [[ShouldInit2 alloc] init]; 124 | assert(called); 125 | 126 | called = NO; 127 | [[ShouldInitSubclassed alloc] init]; 128 | assert(called); 129 | 130 | called = NO; 131 | [NoAlloc alloc]; 132 | assert(!called); 133 | 134 | [NoAlloc allocWithZone: NULL]; 135 | assert(!called); 136 | called = NO; 137 | 138 | called = NO; 139 | [[NoInit alloc] init]; 140 | assert(!called); 141 | 142 | called = NO; 143 | [[NoInit2 alloc] init]; 144 | assert(!called); 145 | 146 | // Look up a non-existing class to test if fast-path 147 | // implementations can handle receivers that are nil 148 | [getClassNamed("flibble") alloc]; 149 | [[getClassNamed("flibble") alloc] init]; 150 | } 151 | 152 | #endif 153 | -------------------------------------------------------------------------------- /Test/ForeignException.m: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | #include "../unwind.h" 3 | 4 | #if __cplusplus 5 | #error This is not an ObjC++ test! 6 | #endif 7 | 8 | struct 9 | { 10 | struct _Unwind_Exception header; 11 | id x; 12 | } foreign_exception; 13 | 14 | BOOL cleanup_called = NO; 15 | BOOL finally_called = NO; 16 | 17 | static void cleanup(_Unwind_Reason_Code i,struct _Unwind_Exception *e) 18 | { 19 | assert(e == &foreign_exception.header); 20 | cleanup_called = YES; 21 | } 22 | 23 | int throw(void) 24 | { 25 | foreign_exception.header.exception_class = 42; 26 | foreign_exception.header.exception_cleanup = cleanup; 27 | foreign_exception.x = (id)12; 28 | _Unwind_RaiseException(&foreign_exception.header); 29 | assert(0); 30 | } 31 | 32 | void finally(void) 33 | { 34 | @try 35 | { 36 | throw(); 37 | } 38 | @finally 39 | { 40 | finally_called = YES; 41 | } 42 | finally_called = NO; 43 | } 44 | 45 | 46 | int main(void) 47 | { 48 | BOOL catchall = NO; 49 | @try 50 | { 51 | finally(); 52 | } 53 | @catch (id x) 54 | { 55 | assert(0); 56 | } 57 | @catch(...) 58 | { 59 | catchall = YES; 60 | } 61 | assert(finally_called == YES); 62 | assert(catchall == YES); 63 | assert(cleanup_called == YES); 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /Test/Forward.m: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | #include "../objc/hooks.h" 3 | 4 | @interface Forward : Test 5 | - (id)forwardingTargetForSelector: (SEL)sel; 6 | @end 7 | 8 | id target; 9 | 10 | @implementation Forward 11 | - (id)forwardingTargetForSelector: (SEL)sel 12 | { 13 | return target; 14 | } 15 | @end 16 | 17 | @interface Forward2 : Test 18 | @end 19 | 20 | @interface ForwardingTarget : Test 21 | { 22 | int y; 23 | } 24 | @end 25 | 26 | BOOL forwardingTargetCalled; 27 | 28 | @implementation ForwardingTarget 29 | - (id)init 30 | { 31 | y = 42; 32 | return self; 33 | } 34 | 35 | - (void)foo: (int)x 36 | { 37 | assert(x == 42); 38 | assert(x == y); 39 | forwardingTargetCalled = YES; 40 | } 41 | @end 42 | @implementation Forward2 43 | - (void)forward: (int)x 44 | { 45 | [target foo: x]; 46 | } 47 | @end 48 | 49 | static id proxy_lookup(id receiver, SEL selector) 50 | { 51 | if (class_respondsToSelector(object_getClass(receiver), @selector(forwardingTargetForSelector:))) 52 | { 53 | return [receiver forwardingTargetForSelector: selector]; 54 | } 55 | return nil; 56 | } 57 | 58 | static IMP forward(id receiver, SEL selector) 59 | { 60 | if (class_respondsToSelector(object_getClass(receiver), @selector(forward:))) 61 | { 62 | return class_getMethodImplementation(object_getClass(receiver), @selector(forward:)); 63 | } 64 | assert(0); 65 | } 66 | 67 | int main(void) 68 | { 69 | objc_proxy_lookup = proxy_lookup; 70 | __objc_msg_forward2 = forward; 71 | target = [[ForwardingTarget new] init]; 72 | id proxy = [Forward new]; 73 | [proxy foo: 42]; 74 | [proxy dealloc]; 75 | assert(forwardingTargetCalled == YES); 76 | forwardingTargetCalled = NO; 77 | proxy = [Forward2 new]; 78 | [proxy foo: 42]; 79 | [proxy dealloc]; 80 | assert(forwardingTargetCalled == YES); 81 | } 82 | -------------------------------------------------------------------------------- /Test/ForwardDeclareProtocol.m: -------------------------------------------------------------------------------- 1 | #pragma clang diagnostic ignored "-Wat-protocol" 2 | @protocol P; 3 | 4 | Protocol *getProtocol(void) 5 | { 6 | // Don't try to compile this on known-broken compilers. 7 | #if !defined(__clang__) 8 | return @protocol(P); 9 | // Clang versions before 7 are broken, clang versions after 7 regard this 10 | // as a hard error and will refuse to compile it. 11 | #elif __clang_major__ == 7 12 | return @protocol(P); 13 | #else 14 | return 0; 15 | #endif 16 | } 17 | -------------------------------------------------------------------------------- /Test/ForwardDeclareProtocolAccess.m: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | 3 | @protocol P 4 | - (void)someMethod; 5 | @end 6 | 7 | // Defined in another compilation unit. Returns @protocol(P). 8 | Protocol *getProtocol(void); 9 | 10 | int main(void) 11 | { 12 | Protocol *p1 = @protocol(P); 13 | Protocol *p2 = getProtocol(); 14 | if (p2 == NULL) 15 | { 16 | return 0; 17 | } 18 | assert(protocol_isEqual(p1, p2)); 19 | #ifdef GS_RUNTIME_V2 20 | // With the new ABI, these should be precisely the same object. 21 | assert(p1 == p2); 22 | unsigned int count; 23 | protocol_copyMethodDescriptionList(p2, YES, YES, &count); 24 | // We did get the correct protocol! 25 | assert(count == 1); 26 | #endif 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /Test/GNUmakefile: -------------------------------------------------------------------------------- 1 | include $(GNUSTEP_MAKEFILES)/common.make 2 | 3 | TOOL_NAME = RuntimeTest 4 | 5 | RuntimeTest_OBJC_FILES=\ 6 | RuntimeTest.m 7 | 8 | include $(GNUSTEP_MAKEFILES)/tool.make 9 | -------------------------------------------------------------------------------- /Test/IVarOverlap.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "../objc/runtime.h" 3 | #include "Test.h" 4 | 5 | #import 6 | #import 7 | 8 | @interface Dummy : Test 9 | { 10 | id objOne; 11 | struct stat statBuf; 12 | BOOL flagOne; 13 | } 14 | @end 15 | 16 | @implementation Dummy 17 | - (void)test 18 | { 19 | assert((char*)&statBuf+sizeof(struct stat) <= (char*)&flagOne); 20 | } 21 | @end 22 | 23 | 24 | int main(int argc, char *argv[]) 25 | { 26 | [[Dummy new] test]; 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /Test/IVarSuperclassOverlap.m: -------------------------------------------------------------------------------- 1 | #import "../objc/runtime.h" 2 | #include "Test.h" 3 | 4 | @interface Space : Test 5 | { 6 | uint16_t baseSmall; 7 | } 8 | @end 9 | 10 | @interface StartsWithChar : Space 11 | { 12 | char c1; 13 | char c2; 14 | char c3; 15 | } 16 | @end 17 | @interface StartsWithBitfield : Space 18 | { 19 | @public 20 | uint16_t b1:4; 21 | uint16_t b2:4; 22 | uint16_t b3:4; 23 | uint16_t b4:4; 24 | uint16_t notBitfield; 25 | } 26 | @end 27 | 28 | @implementation Space @end 29 | @implementation StartsWithChar @end 30 | @implementation StartsWithBitfield @end 31 | 32 | int main(int argc, char *argv[]) 33 | { 34 | Class s = objc_getClass("Space"); 35 | assert(s); 36 | Class swc = objc_getClass("StartsWithChar"); 37 | assert(swc); 38 | Class swb = objc_getClass("StartsWithBitfield"); 39 | assert(swb); 40 | Ivar baseSmall = class_getInstanceVariable(s, "baseSmall"); 41 | Ivar c1 = class_getInstanceVariable(swc, "c1"); 42 | Ivar c2 = class_getInstanceVariable(swc, "c2"); 43 | Ivar c3 = class_getInstanceVariable(swc, "c3"); 44 | Ivar b1 = class_getInstanceVariable(swb, "b1"); 45 | Ivar b2 = class_getInstanceVariable(swb, "b2"); 46 | Ivar b3 = class_getInstanceVariable(swb, "b3"); 47 | Ivar b4 = class_getInstanceVariable(swb, "b4"); 48 | Ivar notBitfield = class_getInstanceVariable(swb, "notBitfield"); 49 | assert(baseSmall); 50 | assert(c1); 51 | assert(c2); 52 | assert(c3); 53 | assert(b1); 54 | assert(b2); 55 | assert(b3); 56 | assert(b4); 57 | assert(notBitfield); 58 | StartsWithBitfield *swbi = [StartsWithBitfield new]; 59 | 60 | // Alternating 01 bit pattern, should catch small overwrites. 61 | swbi->notBitfield = 0x5555; 62 | swbi->b1 = 5; 63 | swbi->b2 = 11; 64 | swbi->b3 = 11; 65 | swbi->b4 = 5; 66 | assert(swbi->b1 == 5); 67 | assert(swbi->b2 == 11); 68 | assert(swbi->b3 == 11); 69 | assert(swbi->b4 == 5); 70 | assert(swbi->notBitfield == 0x5555); 71 | swbi->notBitfield = 0xaaaa; 72 | swbi->b1 = 5; 73 | swbi->b2 = 11; 74 | swbi->b3 = 5; 75 | swbi->b4 = 11; 76 | assert(swbi->notBitfield == 0xaaaa); 77 | assert(swbi->b1 == 5); 78 | assert(swbi->b2 == 11); 79 | assert(swbi->b3 == 5); 80 | assert(swbi->b4 == 11); 81 | 82 | #ifdef NEW_ABI 83 | ptrdiff_t baseSmallOffset = ivar_getOffset(baseSmall); 84 | // These should pass with the old ABI, but they don't at the moment. The 85 | // way that they don't is not very harmful though: we just get a bit of 86 | // redundant padding, so I don't consider a fix a very high priority. 87 | assert(ivar_getOffset(c1) == baseSmallOffset + 2); 88 | assert(ivar_getOffset(c2) == baseSmallOffset + 3); 89 | assert(ivar_getOffset(c3) == baseSmallOffset + 4); 90 | assert(ivar_getOffset(b1) == baseSmallOffset + 2); 91 | assert(ivar_getOffset(b2) == baseSmallOffset + 2); 92 | assert(ivar_getOffset(b3) == baseSmallOffset + 3); 93 | assert(ivar_getOffset(b4) == baseSmallOffset + 3); 94 | assert(ivar_getOffset(notBitfield) == baseSmallOffset + 4); 95 | #endif 96 | 97 | 98 | return 0; 99 | } 100 | -------------------------------------------------------------------------------- /Test/ManyManySelectors.m: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | #include 3 | #include 4 | #include 5 | #include "../selector.h" 6 | 7 | #include 8 | 9 | 10 | static BOOL methodCalled = NO; 11 | 12 | static char selBuffer[] = "XXXXXXXselectorXXXXXXXX"; 13 | 14 | static id x(id self, SEL _cmd) 15 | { 16 | methodCalled = YES; 17 | if (strcmp(selBuffer, sel_getName(_cmd)) != 0) 18 | { 19 | fprintf(stderr, "'%s' != '%s'\n", selBuffer, sel_getName(_cmd)); 20 | } 21 | assert(strcmp(selBuffer, sel_getName(_cmd)) == 0); 22 | return self; 23 | } 24 | 25 | int main(void) 26 | { 27 | 28 | SEL nextSel; 29 | Class cls = [Test class]; 30 | assert(cls != Nil); 31 | int sel_size = 0; 32 | for (uint32_t i=0 ; i<0xf0000 ; i++) 33 | { 34 | snprintf(selBuffer, sizeof(selBuffer), "%" PRId32 "selector%" PRIx32, i, i); 35 | nextSel = sel_registerName(selBuffer); 36 | char *registeredName = sel_getName(nextSel); 37 | if (strcmp(selBuffer, registeredName) != 0) 38 | { 39 | fprintf(stderr, "'%s' != '%s' (%p)\n", selBuffer, registeredName, nextSel->index); 40 | } 41 | assert(strcmp(selBuffer, sel_getName(nextSel)) == 0); 42 | sel_size += strlen(selBuffer); 43 | } 44 | assert(class_addMethod(object_getClass([Test class]), nextSel, (IMP)x, "@@:")); 45 | assert(cls == [Test class]); 46 | // Test both the C and assembly code paths. 47 | objc_msg_lookup(cls, nextSel)(cls, nextSel); 48 | assert(methodCalled == YES); 49 | methodCalled = NO; 50 | #ifdef __GNUSTEP_MSGSEND__ 51 | objc_msgSend([Test class], nextSel); 52 | assert(methodCalled == YES); 53 | #endif 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /Test/MethodArguments.m: -------------------------------------------------------------------------------- 1 | #import "Test.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #ifdef __has_attribute 8 | #if __has_attribute(objc_root_class) 9 | __attribute__((objc_root_class)) 10 | #endif 11 | #endif 12 | @interface Foo 13 | -(id)bar; 14 | -(void)setBar:(id)b; 15 | @end 16 | @implementation Foo 17 | - (id)bar 18 | { 19 | return nil; 20 | } 21 | 22 | - (void)setBar: (id)b 23 | { 24 | return; 25 | } 26 | @end 27 | 28 | int main(void) 29 | { 30 | Class foo = objc_getClass("Foo"); 31 | Method barMethod = class_getInstanceMethod(foo, @selector(bar)); 32 | Method setBarMethod = class_getInstanceMethod(foo,@selector(setBar:)); 33 | char arg[16]; 34 | 35 | memset(&arg[0], '\0', 16 * sizeof(char)); 36 | method_getReturnType(barMethod, &arg[0], 16); 37 | assert(0 == strcmp(&arg[0],"@")); 38 | 39 | char* expected[3] = {"@", ":", "" }; 40 | for (int i = 0; i < 3; i++) 41 | { 42 | memset(&arg[0], '\0', 16 * sizeof(char)); 43 | method_getArgumentType(barMethod, i, &arg[0], 16); 44 | assert(0 == strcmp(&arg[0],expected[i])); 45 | } 46 | 47 | 48 | memset(&arg[0], '\0', 16 * sizeof(char)); 49 | method_getReturnType(setBarMethod, &arg[0], 16); 50 | assert(0 == strcmp(&arg[0],"v")); 51 | 52 | expected[2] = "@"; 53 | 54 | for (int i = 0; i < 3; i++) 55 | { 56 | memset(&arg[0], '\0', 16 * sizeof(char)); 57 | method_getArgumentType(setBarMethod, i, &arg[0], 16); 58 | assert(0 == strcmp(&arg[0],expected[i])); 59 | } 60 | 61 | char *arg_copied = method_copyReturnType(barMethod); 62 | assert(0 == strcmp(arg_copied,"@")); 63 | free(arg_copied); 64 | arg_copied = NULL; 65 | 66 | for (int i = 0; i < 2; i++) 67 | { 68 | arg_copied = method_copyArgumentType(barMethod, i); 69 | assert(0 == strcmp(arg_copied,expected[i])); 70 | free(arg_copied); 71 | } 72 | 73 | arg_copied = method_copyArgumentType(barMethod, 2); 74 | assert(NULL == arg_copied); 75 | 76 | 77 | 78 | arg_copied = method_copyReturnType(setBarMethod); 79 | assert(0 == strcmp(arg_copied,"v")); 80 | free(arg_copied); 81 | 82 | for (int i = 0; i < 3; i++) 83 | { 84 | arg_copied = method_copyArgumentType(setBarMethod, i); 85 | assert(0 == strcmp(arg_copied,expected[i])); 86 | free(arg_copied); 87 | } 88 | 89 | 90 | return 0; 91 | } 92 | -------------------------------------------------------------------------------- /Test/NestedExceptions.m: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | 3 | #if __cplusplus 4 | #error This is not an ObjC++ test! 5 | #endif 6 | 7 | 8 | id a; 9 | int throw(void) 10 | { 11 | @throw a; 12 | } 13 | 14 | 15 | int main(void) 16 | { 17 | id e1 = [Test new]; 18 | id e2 = [Test new]; 19 | @try 20 | { 21 | a = e1; 22 | throw(); 23 | } 24 | @catch (id x) 25 | { 26 | assert(x == e1); 27 | @try { 28 | a = e2; 29 | @throw a; 30 | } 31 | @catch (id y) 32 | { 33 | assert(y == e2); 34 | } 35 | } 36 | [e1 dealloc]; 37 | [e2 dealloc]; 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /Test/NilException.m: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | 3 | 4 | #ifdef __has_attribute 5 | #if __has_attribute(objc_root_class) 6 | __attribute__((objc_root_class)) 7 | #endif 8 | #endif 9 | @interface NSObject 10 | { 11 | Class isa; 12 | } 13 | @end 14 | 15 | @implementation NSObject 16 | + (id)new 17 | { 18 | return class_createInstance(self, 0); 19 | } 20 | @end 21 | int main(void) 22 | { 23 | BOOL caught_exception = NO; 24 | @try 25 | { 26 | @throw(nil); 27 | } 28 | @catch (NSObject* o) 29 | { 30 | assert(0); 31 | } 32 | @catch (id x) 33 | { 34 | assert(nil == x); 35 | caught_exception = YES; 36 | } 37 | assert(caught_exception == YES); 38 | caught_exception = NO; 39 | @try 40 | { 41 | @throw(nil); 42 | } 43 | @catch (...) 44 | { 45 | caught_exception = YES; 46 | } 47 | assert(caught_exception == YES); 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /Test/ObjCXXEHInterop.m: -------------------------------------------------------------------------------- 1 | #import "Test.h" 2 | 3 | #import "stdio.h" 4 | 5 | void poke_objcxx(void); 6 | void check_uncaught_count(void); 7 | 8 | void rethrow(id x) 9 | { 10 | @throw x; 11 | } 12 | 13 | int main(void) 14 | { 15 | @try { 16 | printf("Poking from minRepM\n"); 17 | poke_objcxx(); 18 | printf("Poked from minRepM\n"); 19 | } @catch (Test *localException) { 20 | printf("In NS_HANDLER block, %p\n", localException); 21 | } 22 | check_uncaught_count(); 23 | } 24 | 25 | -------------------------------------------------------------------------------- /Test/ObjCXXEHInterop.mm: -------------------------------------------------------------------------------- 1 | #import "Test.h" 2 | #import "stdio.h" 3 | 4 | #ifdef __unix__ 5 | // Declare these inline. The libsupc++ version of cxxabi.h does not include 6 | // __cxa_eh_globls, even though it's mandated by the ABI. 7 | namespace __cxxabiv1 8 | { 9 | struct __cxa_exception; 10 | struct __cxa_eh_globals 11 | { 12 | __cxa_exception *caughtExceptions; 13 | unsigned int uncaughtExceptions; 14 | }; 15 | extern "C" __cxa_eh_globals *__cxa_get_globals(); 16 | } 17 | extern "C" void check_uncaught_count(void) 18 | { 19 | assert(__cxxabiv1::__cxa_get_globals()->uncaughtExceptions == 0); 20 | } 21 | #else 22 | extern "C" void check_uncaught_count(void) {} 23 | #endif 24 | 25 | extern "C" void rethrow(id); 26 | 27 | 28 | extern "C" void poke_objcxx(void) 29 | { 30 | @try { 31 | printf("Raising MyException\n"); 32 | Test *e = [Test new]; 33 | @throw e; 34 | } @catch (Test *localException) { 35 | printf("Caught - re-raising\n"); 36 | [localException retain]; 37 | localException = [localException autorelease];; 38 | rethrow(localException); 39 | } 40 | } 41 | 42 | -------------------------------------------------------------------------------- /Test/ObjCXXEHInteropTwice.mm: -------------------------------------------------------------------------------- 1 | #import "Test.h" 2 | 3 | #import "stdio.h" 4 | 5 | 6 | void excerciseExceptionCXX(Test *e) { 7 | @try { 8 | printf("Raising Test\n"); 9 | @throw e; 10 | } @catch (Test *localException) { 11 | printf("Caught\n"); 12 | } 13 | } 14 | 15 | int main(void) 16 | { 17 | Test *e = [Test new]; 18 | excerciseExceptionCXX(e); 19 | excerciseExceptionCXX(e); 20 | [e release]; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /Test/ObjCXXEHInterop_arc.m: -------------------------------------------------------------------------------- 1 | #import "Test.h" 2 | 3 | #import "stdio.h" 4 | 5 | void poke_objcxx(void); 6 | 7 | void rethrow(id x) 8 | { 9 | @throw x; 10 | } 11 | 12 | int main(void) 13 | { 14 | @try { 15 | printf("Poking from minRepM\n"); 16 | poke_objcxx(); 17 | printf("Poked from minRepM\n"); 18 | } @catch (Test *localException) { 19 | printf("In NS_HANDLER block, %p\n", localException); 20 | } 21 | } 22 | 23 | -------------------------------------------------------------------------------- /Test/ObjCXXEHInterop_arc.mm: -------------------------------------------------------------------------------- 1 | #import "Test.h" 2 | #import "stdio.h" 3 | 4 | extern "C" void rethrow(id); 5 | 6 | 7 | extern "C" void poke_objcxx(void) 8 | { 9 | @try { 10 | printf("Raising MyException\n"); 11 | Test *e = [Test new]; 12 | @throw e; 13 | } @catch (Test *localException) { 14 | printf("Caught - re-raising\n"); 15 | rethrow(localException); 16 | } 17 | } 18 | 19 | -------------------------------------------------------------------------------- /Test/PropertyAttributeTest.m: -------------------------------------------------------------------------------- 1 | #include 2 | #import "Test.h" 3 | #include 4 | #include 5 | #include 6 | 7 | @protocol X 8 | @optional 9 | @property (readonly) int x; 10 | @end 11 | 12 | #ifdef __has_attribute 13 | #if __has_attribute(objc_root_class) 14 | __attribute__((objc_root_class)) 15 | #endif 16 | #endif 17 | 18 | @interface helloclass { 19 | @private int varName; 20 | } 21 | @property (class, retain) id clsProp; 22 | @property (readwrite,assign) int propName; 23 | @end 24 | 25 | @implementation helloclass 26 | @synthesize propName = varName; 27 | + (id)class { return self; } 28 | + (id)clsProp { return nil; } 29 | + (void)setClsProp: (id)arg {} 30 | @end 31 | 32 | int main() 33 | { 34 | unsigned int outCount; 35 | objc_property_t *properties = class_copyPropertyList([helloclass class], &outCount); 36 | assert(outCount == 1); 37 | objc_property_t property = properties[0]; 38 | assert(strcmp(property_getName(property), "propName") == 0); 39 | assert(strcmp(property_getAttributes(property), "Ti,VvarName") == 0); 40 | free(properties); 41 | 42 | properties = class_copyPropertyList(object_getClass([helloclass class]), &outCount); 43 | assert(outCount == 1); 44 | property = properties[0]; 45 | assert(strcmp(property_getName(property), "clsProp") == 0); 46 | fprintf(stderr, "%s\n", property_getAttributes(property)); 47 | assert(strcmp(property_getAttributes(property), "T@,&") == 0); 48 | free(properties); 49 | 50 | Method* methods = class_copyMethodList([helloclass class], &outCount); 51 | // This metadata was buggy in clang versions prior to clang 11. 52 | #if __clang_major__ > 10 53 | assert(outCount == 2); 54 | #endif 55 | free(methods); 56 | 57 | objc_property_attribute_t a = { "V", "varName" }; 58 | assert(class_addProperty([helloclass class], "propName2", &a, 1)); 59 | properties = class_copyPropertyList([helloclass class], &outCount); 60 | assert(outCount == 2); 61 | int found = 0; 62 | for (int i=0 ; i<2 ; i++) 63 | { 64 | property = properties[i]; 65 | fprintf(stderr, "Name: %s\n", property_getName(property)); 66 | fprintf(stderr, "Attrs: %s\n", property_getAttributes(property)); 67 | if (strcmp(property_getName(property), "propName2") == 0) 68 | { 69 | assert(strcmp(property_getAttributes(property), "VvarName") == 0); 70 | found++; 71 | } 72 | } 73 | assert(found == 1); 74 | return 0; 75 | } 76 | 77 | 78 | -------------------------------------------------------------------------------- /Test/PropertyIntrospectionTest.m: -------------------------------------------------------------------------------- 1 | #import "Test.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #ifdef __has_attribute 7 | #if __has_attribute(objc_root_class) 8 | __attribute__((objc_root_class)) 9 | #endif 10 | #endif 11 | @interface Foo 12 | @property (getter=bar, setter=setBar:, nonatomic, copy) id foo; 13 | @end 14 | @interface Foo(Bar) 15 | -(id)bar; 16 | -(void)setBar:(id)b; 17 | @end 18 | @implementation Foo 19 | @synthesize foo; 20 | @end 21 | 22 | int main(void) 23 | { 24 | objc_property_t p = class_getProperty(objc_getClass("Foo"), "foo"); 25 | unsigned int count; 26 | objc_property_attribute_t *l = property_copyAttributeList(p, &count); 27 | for (unsigned int i=0 ; i 3 | 4 | @class NSString; 5 | @protocol Foo 6 | - (NSString*)aMethod: (void(^)(int))aBlock; 7 | @end 8 | 9 | int main(void) 10 | { 11 | const char *encoding = _protocol_getMethodTypeEncoding(@protocol(Foo), @selector(aMethod:), YES, YES); 12 | #ifdef GS_RUNTIME_V2 13 | // We expect something like this (LP64): @"NSString"24@0:8@?16 14 | assert(strstr(encoding, "@\"NSString\"") == encoding); 15 | assert(strstr(encoding, "@?") != NULL); 16 | #else 17 | assert(strstr(encoding, "@?") != NULL); 18 | #endif 19 | } 20 | -------------------------------------------------------------------------------- /Test/ResurrectInDealloc_arc.m: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Test.h" 3 | 4 | @interface DieStrong : Test @end 5 | @interface DieWeak : Test @end 6 | @implementation DieStrong 7 | - (void)dealloc 8 | { 9 | fprintf(stderr, "Killing strong\n"); 10 | void (^myBlock)() = ^() 11 | { 12 | id foo = self; 13 | fprintf(stderr, "strong self: %p\n", foo); 14 | }; 15 | myBlock(); 16 | } 17 | @end 18 | 19 | @implementation DieWeak 20 | - (void)dealloc 21 | { 22 | fprintf(stderr, "Killing weak\n"); 23 | __weak id this = self; 24 | void (^myBlock)() = ^() 25 | { 26 | id foo = this; 27 | fprintf(stderr, "weak self: %p\n", foo); 28 | }; 29 | myBlock(); 30 | } 31 | @end 32 | 33 | int main(void) 34 | { 35 | fprintf(stderr, "Test running?\n"); 36 | id a = [DieStrong new], b = [DieWeak new]; 37 | a = nil; 38 | b = nil; 39 | } 40 | -------------------------------------------------------------------------------- /Test/SuperMethodMissing.m: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | #include "objc/hooks.h" 3 | #include 4 | 5 | @interface Test (DoesNotExist) 6 | - (void)run; 7 | @end 8 | 9 | @interface Foo : Test 10 | @end 11 | 12 | @implementation Foo 13 | - (void)run 14 | { 15 | [super run]; 16 | } 17 | @end 18 | 19 | static int missing_methods; 20 | 21 | id forward(id self, SEL cmd, ...) 22 | { 23 | Class cls = object_getClass(self); 24 | missing_methods++; 25 | fprintf(stderr, "Missing method: %c[%s %s]\n", class_isMetaClass(cls) ? '+' : '-', class_getName(cls),sel_getName(cmd)); 26 | return nil; 27 | } 28 | 29 | IMP no_method(id self, SEL cmd) 30 | { 31 | return forward; 32 | } 33 | 34 | 35 | int 36 | main() 37 | { 38 | __objc_msg_forward2 = no_method; 39 | Test *t = [Test new]; 40 | [t run]; 41 | assert(missing_methods == 1); 42 | Foo *f = [Foo new]; 43 | [f run]; 44 | assert(missing_methods == 2); 45 | //[Test run]; 46 | } 47 | -------------------------------------------------------------------------------- /Test/Test.h: -------------------------------------------------------------------------------- 1 | #import "../objc/runtime.h" 2 | #import "../objc/objc-arc.h" 3 | #ifdef NDEBUG 4 | #undef NDEBUG 5 | #endif 6 | #include 7 | 8 | #ifndef __has_attribute 9 | #define __has_attribute(x) 0 10 | #endif 11 | 12 | #if __has_attribute(objc_root_class) 13 | __attribute__((objc_root_class)) 14 | #endif 15 | @interface Test { id isa; } 16 | + (Class)class; 17 | + (id)new; 18 | + (id)alloc; 19 | #if !__has_feature(objc_arc) 20 | - (void)dealloc; 21 | - (id)autorelease; 22 | - (id)retain; 23 | - (void)release; 24 | #endif 25 | @end 26 | 27 | #ifdef __OBJC_GNUSTEP_RUNTIME_ABI__ 28 | # if __OBJC_GNUSTEP_RUNTIME_ABI__ >= 20 29 | # define NEW_ABI 30 | # endif 31 | #endif 32 | 33 | @interface NSConstantString : Test 34 | { 35 | #ifdef NEW_ABI 36 | uint32_t flags; 37 | uint32_t length; 38 | uint32_t size; 39 | uint32_t hash; 40 | const char * const str; 41 | #else 42 | const char * const str; 43 | const unsigned int length; 44 | #endif 45 | } 46 | @end 47 | 48 | @interface NSAutoreleasePool : Test 49 | @end 50 | 51 | 52 | -------------------------------------------------------------------------------- /Test/Test.m: -------------------------------------------------------------------------------- 1 | #import "../objc/runtime.h" 2 | #import "../objc/objc-arc.h" 3 | #ifdef NDEBUG 4 | #undef NDEBUG 5 | #endif 6 | #include 7 | #include "Test.h" 8 | 9 | @implementation NSConstantString 10 | - (void)dealloc 11 | { 12 | // Silence a warning 13 | if (0) 14 | { 15 | [super dealloc]; 16 | } 17 | } 18 | @end 19 | 20 | @interface NSTinyString : NSConstantString @end 21 | @implementation NSTinyString 22 | + (void)load 23 | { 24 | if (sizeof(void*) > 4) 25 | { 26 | objc_registerSmallObjectClass_np(self, 4); 27 | } 28 | } 29 | - (Class)class { return [NSTinyString class]; } 30 | - (id)retain { return self; } 31 | - (id)autorelease { return self; } 32 | - (void)release {} 33 | @end 34 | 35 | @implementation Test 36 | + (Class)class { return self; } 37 | + (id)new 38 | { 39 | return class_createInstance(self, 0); 40 | } 41 | + (id)alloc 42 | { 43 | return class_createInstance(self, 0); 44 | } 45 | - (void)dealloc 46 | { 47 | object_dispose(self); 48 | } 49 | - (id)autorelease 50 | { 51 | return objc_autorelease(self); 52 | } 53 | - (id)retain 54 | { 55 | return objc_retain(self); 56 | } 57 | - (void)release 58 | { 59 | objc_release(self); 60 | } 61 | - (void)_ARCCompliantRetainRelease {} 62 | + (void)_TrivialAllocInit{} 63 | @end 64 | 65 | @implementation NSAutoreleasePool 66 | - (void)_ARCCompatibleAutoreleasePool {} 67 | + (void)addObject:(id)anObject 68 | { 69 | objc_autorelease(anObject); 70 | } 71 | @end 72 | -------------------------------------------------------------------------------- /Test/UnexpectedException.m: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | #include "../objc/hooks.h" 3 | #include "../objc/objc-exception.h" 4 | 5 | #include 6 | 7 | #ifdef _WIN32 8 | #include 9 | #endif 10 | 11 | id expectedExceptionObj = @"ExpectedException"; 12 | id unexpectedExceptionObj = @"UnexpectedException"; 13 | 14 | void _UncaughtExceptionHandler(id exception) 15 | { 16 | assert(exception == unexpectedExceptionObj); 17 | #if defined(_WIN32) && !defined(__MINGW32__) 18 | // on Windows we will exit in _UnhandledExceptionFilter() below 19 | #else 20 | exit(0); 21 | #endif 22 | } 23 | 24 | #if defined(_WIN32) && !defined(__MINGW32__) 25 | LONG WINAPI _UnhandledExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) 26 | { 27 | assert(exceptionInfo != NULL); 28 | exit(0); 29 | } 30 | #endif 31 | 32 | int main(void) 33 | { 34 | #if !(defined(__arm__) || defined(__ARM_ARCH_ISA_A64)) && !defined(__powerpc__) 35 | #if defined(_WIN32) && !defined(__MINGW32__) 36 | // also verify that an existing handler still gets called after we set ours 37 | SetUnhandledExceptionFilter(&_UnhandledExceptionFilter); 38 | #endif 39 | @try 40 | { 41 | @throw expectedExceptionObj; 42 | } 43 | @catch(id exception) 44 | { 45 | assert(exception == expectedExceptionObj); 46 | } 47 | 48 | objc_setUncaughtExceptionHandler(_UncaughtExceptionHandler); 49 | @throw unexpectedExceptionObj; 50 | assert(0 && "should not be reached!"); 51 | 52 | return -1; 53 | #endif 54 | // FIXME: Test currently fails on ARM and AArch64 55 | return 77; // Skip test 56 | } 57 | -------------------------------------------------------------------------------- /Test/WeakBlock_arc.m: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | 3 | int main(int argc, const char * argv[]) 4 | { 5 | id __weak ref; 6 | @autoreleasepool { 7 | __block int val; 8 | id block = ^() { return val++; }; 9 | assert(block != nil); 10 | ref = block; 11 | assert(ref != nil); 12 | } 13 | assert(ref == nil); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /Test/WeakImportClass.m: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | 3 | 4 | __attribute__((weak_import)) 5 | @interface WeakClass 6 | - (id)class; 7 | @end 8 | 9 | int main(void) 10 | { 11 | assert([WeakClass class] == nil); 12 | } 13 | -------------------------------------------------------------------------------- /Test/WeakRefLoad.m: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | 3 | #define SIZE 5000 4 | 5 | int main(int argc, const char * argv[]) 6 | { 7 | id t = [Test new]; 8 | id w1; 9 | id w2; 10 | objc_initWeak(&w1, t); 11 | objc_initWeak(&w2, t); 12 | [t release]; 13 | assert(objc_loadWeakRetained(&w1) == nil); 14 | assert(objc_loadWeakRetained(&w2) == nil); 15 | assert(w1 == nil); 16 | assert(w2 == nil); 17 | assert(objc_loadWeakRetained(&w1) == nil); 18 | assert(objc_loadWeakRetained(&w2) == nil); 19 | assert(w1 == nil); 20 | assert(w2 == nil); 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /Test/WeakReferences_arc.m: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | 3 | #define SIZE 5000 4 | 5 | int main(int argc, const char * argv[]) 6 | { 7 | @autoreleasepool { 8 | id __weak refs[SIZE]; 9 | id values[SIZE]; 10 | 11 | // Setup 12 | for (int i=0; ix = (v4d){1,2,3,4}; 28 | return v; 29 | } 30 | - (void)permute 31 | { 32 | // This will become a sequence of one or more vector operations. We must 33 | // have the correct alignment for x, even after the instance variable 34 | // munging, or this will break. 35 | x *= (v4d){2,3,4,5}; 36 | } 37 | @end 38 | 39 | typedef int v4si __attribute__ ((vector_size (16))); 40 | @interface Foo : Test 41 | { 42 | v4si var; 43 | } 44 | - (void)check; 45 | @end 46 | @implementation Foo 47 | - (void)check 48 | { 49 | size_t addr = (size_t)&var; 50 | fprintf(stderr, "self: %p Addr: %p\n", self, &var); 51 | assert(addr % __alignof__(v4si) == 0); 52 | } 53 | @end 54 | 55 | #if __has_attribute(objc_root_class) 56 | __attribute__((objc_root_class)) 57 | #endif 58 | @interface StringLikeTest 59 | { 60 | Class isa; 61 | char* c_string; 62 | int len; 63 | } 64 | @end 65 | 66 | @implementation StringLikeTest 67 | + (Class)class 68 | { 69 | return self; 70 | } 71 | @end 72 | 73 | int main(void) 74 | { 75 | [[Vector alloc] permute]; 76 | [[Foo new] check]; 77 | 78 | Ivar v_isa = class_getInstanceVariable([StringLikeTest class], "isa"); 79 | Ivar v_c_string = class_getInstanceVariable([StringLikeTest class], "c_string"); 80 | Ivar v_len = class_getInstanceVariable([StringLikeTest class], "len"); 81 | ptrdiff_t o_isa = ivar_getOffset(v_isa); 82 | ptrdiff_t o_c_string = ivar_getOffset(v_c_string); 83 | assert(o_isa == 0); 84 | assert(o_c_string == sizeof(Class)); 85 | assert(o_isa < o_c_string); 86 | assert(o_c_string < ivar_getOffset(v_len)); 87 | } 88 | -------------------------------------------------------------------------------- /Test/category_properties.m: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | #include 3 | #include 4 | 5 | @interface Test (Property) 6 | @property (readonly) int val; 7 | @property (class, readonly) int val2; 8 | @end 9 | 10 | @interface Test (Property2) 11 | @property (readonly) int val2; 12 | @end 13 | 14 | 15 | @implementation Test (Property) 16 | @dynamic val2; 17 | - (int)val { return 0; } 18 | @end 19 | 20 | @implementation Test (Property2) 21 | @dynamic val2; 22 | - (int)val2 { return 0; } 23 | @end 24 | 25 | int main(int argc, char** argv) 26 | { 27 | Class test = objc_getClass("Test"); 28 | objc_property_t prop = class_getProperty(test, "val"); 29 | assert(prop); 30 | assert(strcmp("Ti,R", property_getAttributes(prop)) == 0); 31 | prop = class_getProperty(test, "val2"); 32 | assert(prop); 33 | assert(strcmp("Ti,R,D", property_getAttributes(prop)) == 0); 34 | #ifdef GS_RUNTIME_V2 35 | test = object_getClass(test); 36 | prop = class_getProperty(test, "val2"); 37 | assert(prop); 38 | assert(strcmp("Ti,R,D", property_getAttributes(prop)) == 0); 39 | #endif 40 | } 41 | 42 | -------------------------------------------------------------------------------- /Test/exchange.m: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | 3 | @interface Exchange : Test 4 | + (int)test1; 5 | + (int)test2; 6 | @end 7 | 8 | @implementation Exchange 9 | + (void)noop { } 10 | 11 | + (int)test1 { return 1024; } 12 | + (int)test2 { return 2048; } 13 | @end 14 | 15 | int main(int argc, char** argv) { 16 | [Exchange noop]; 17 | Class i32meta = object_getClass(objc_getClass("Exchange")); 18 | Method m1 = class_getInstanceMethod(i32meta, @selector(test1)); 19 | Method m2 = class_getInstanceMethod(i32meta, @selector(test2)); 20 | method_exchangeImplementations(m1, m2); 21 | assert(2048 == [Exchange test1]); 22 | } 23 | 24 | -------------------------------------------------------------------------------- /Test/hash_table_delete.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct test_struct { 5 | uintptr_t key; 6 | }; 7 | 8 | struct test_struct null_placeholder = {0}; 9 | 10 | static int test_compare(const void *key, const struct test_struct test) { 11 | return (uintptr_t)key == test.key; 12 | } 13 | 14 | // force hash collisions 15 | static uint32_t test_key_hash(const void *ptr) { 16 | return ((uint32_t)(uintptr_t)ptr)>>2; 17 | } 18 | 19 | static uint32_t test_value_hash(const struct test_struct test) { 20 | return test.key>>2; 21 | } 22 | 23 | static int test_is_null(const struct test_struct test) { 24 | return test.key == 0; 25 | } 26 | 27 | #define MAP_TABLE_NAME test 28 | #define MAP_TABLE_COMPARE_FUNCTION test_compare 29 | #define MAP_TABLE_VALUE_TYPE struct test_struct 30 | #define MAP_TABLE_VALUE_NULL test_is_null 31 | #define MAP_TABLE_HASH_KEY test_key_hash 32 | #define MAP_TABLE_HASH_VALUE test_value_hash 33 | #define MAP_TABLE_VALUE_PLACEHOLDER null_placeholder 34 | #define MAP_TABLE_ACCESS_BY_REFERENCE 1 35 | #define MAP_TABLE_SINGLE_THREAD 1 36 | #define MAP_TABLE_NO_LOCK 1 37 | 38 | #include "../hash_table.h" 39 | 40 | int main(int argc, char *argv[]) 41 | { 42 | test_table *testTable; 43 | test_initialize(&testTable, 128); 44 | 45 | struct test_struct one, two, three; 46 | one.key = 1; 47 | two.key = 2; 48 | three.key = 3; 49 | 50 | test_insert(testTable, one); 51 | test_insert(testTable, two); 52 | test_insert(testTable, three); 53 | 54 | test_remove(testTable, (void*)2); 55 | test_remove(testTable, (void*)1); 56 | 57 | struct test_struct *pthree = test_table_get(testTable, (void*)3); 58 | if (!pthree) { 59 | fprintf(stderr, "failed to find value (key=3) inserted into hash table\n"); 60 | return 1; 61 | } 62 | 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /Test/hash_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static int compare(const void *i1, uint32_t i2) 5 | { 6 | return ((uint32_t)(uintptr_t)i1) == i2; 7 | } 8 | 9 | static uint32_t hash_int(uint32_t i) 10 | { 11 | return i; 12 | } 13 | static uint32_t hash_key(const void *i) 14 | { 15 | return hash_int((uint32_t)(uintptr_t)i); 16 | } 17 | 18 | static int is_null(uint32_t i) 19 | { 20 | return i == 0; 21 | } 22 | 23 | #define MAP_TABLE_NAME test 24 | #define MAP_TABLE_COMPARE_FUNCTION compare 25 | #define MAP_TABLE_VALUE_TYPE uint32_t 26 | #define MAP_TABLE_VALUE_PLACEHOLDER 0 27 | #define MAP_TABLE_VALUE_NULL is_null 28 | #define MAP_TABLE_HASH_KEY hash_key 29 | #define MAP_TABLE_HASH_VALUE hash_int 30 | #define MAP_TABLE_SINGLE_THREAD 1 31 | #define MAP_TABLE_NO_LOCK 1 32 | 33 | #include "../hash_table.h" 34 | 35 | static test_table *table; 36 | 37 | 38 | void check_table() 39 | { 40 | int count = 0; 41 | for (int i=0 ; itable_size ; i++) 42 | { 43 | struct test_table_cell_struct *s = &table->table[i]; 44 | uint32_t v = ((uint32_t)s->value); 45 | if (v != 0) 46 | { 47 | count++; 48 | assert(v == test_table_get(table, (void*)(uintptr_t)v)); 49 | } 50 | else 51 | { 52 | assert(s->secondMaps == 0); 53 | } 54 | } 55 | assert(count == table->table_used); 56 | } 57 | 58 | int main(void) 59 | { 60 | test_initialize(&table, 128); 61 | const int step = 2; 62 | // 10 iterations was enough to hit the failing case previously. For 63 | // extra paranoia, we can run this test a lot. 64 | const int max = 65 | #ifdef SLOW_TESTS 66 | 8096; 67 | #else 68 | 10; 69 | #endif 70 | for (int seed = 0 ; seed < max ; seed++) 71 | { 72 | fprintf(stderr, "Seed: %d\n", seed); 73 | srand(seed); 74 | for (uint32_t i=1 ; i<5000 ; i+=step) 75 | { 76 | int x = rand(); 77 | if (x == 0) 78 | { 79 | continue; 80 | } 81 | test_insert(table, x); 82 | check_table(); 83 | } 84 | srand(seed); 85 | for (uint32_t i=1 ; i<5000 ; i+=step) 86 | { 87 | int x = rand(); 88 | if (x == 0) 89 | { 90 | continue; 91 | } 92 | test_remove(table, (void*)(uintptr_t)x); 93 | check_table(); 94 | } 95 | assert(table->table_used == 0); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /Test/ivar_arc.m: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | #include "../objc/runtime.h" 3 | 4 | @interface Foo : Test 5 | { 6 | @public 7 | __weak id w; 8 | __unsafe_unretained id u; 9 | __strong id s; 10 | } 11 | @end 12 | @implementation Foo @end 13 | @interface Dealloc : Test 14 | @end 15 | int dealloc = 0; 16 | @implementation Dealloc 17 | - (void)dealloc 18 | { 19 | dealloc++; 20 | } 21 | @end 22 | 23 | @interface EmptySubFoo : Foo 24 | @end 25 | 26 | @implementation EmptySubFoo 27 | @end 28 | 29 | @interface NonEmptySubFoo : Foo 30 | { 31 | __strong id ignored; 32 | } 33 | @end 34 | 35 | @implementation NonEmptySubFoo 36 | @end 37 | 38 | void setIvar(id obj, const char * name, id val) 39 | { 40 | object_setIvar(obj, class_getInstanceVariable(object_getClass(obj), name), val); 41 | } 42 | 43 | void testIvarsOn(Foo* f) 44 | { 45 | dealloc = 0; 46 | Dealloc *d = [Dealloc new]; 47 | __unsafe_unretained Dealloc *dead; 48 | setIvar(f, "w", d); 49 | assert(f->w == d); 50 | assert(dealloc == 0); 51 | d = 0; 52 | assert(dealloc == 1); 53 | assert(f->w == nil); 54 | dealloc = 0; 55 | d = [Dealloc new]; 56 | dead = d; 57 | setIvar(f, "s", d); 58 | assert(dealloc == 0); 59 | assert(f->s == d); 60 | d = nil; 61 | assert(dealloc == 0); 62 | assert(f->s == dead); 63 | setIvar(f, "s", nil); 64 | assert(dealloc == 1); 65 | assert(f->s == nil); 66 | } 67 | 68 | int main (void) 69 | { 70 | /* Test for ivars in the same class */ 71 | testIvarsOn([Foo new]); 72 | /* Test for ivars in the superclass (receiver ivar list empty) */ 73 | testIvarsOn([EmptySubFoo new]); 74 | /* Test for ivars in the superclass (receiver ivar list non-empty) */ 75 | testIvarsOn([NonEmptySubFoo new]); 76 | return 0; 77 | } 78 | -------------------------------------------------------------------------------- /Test/ivar_atomic.m: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | 3 | #import 4 | 5 | @interface Dummy : Test 6 | { 7 | atomic_bool atomicBool; 8 | } 9 | @end 10 | 11 | @implementation Dummy 12 | - (void)test 13 | { 14 | int value = 1; 15 | object_setIvar(self, class_getInstanceVariable(object_getClass(self), "atomicBool"), (__bridge id)(void*)(intptr_t)value); 16 | } 17 | @end 18 | 19 | 20 | int main(int argc, char *argv[]) 21 | { 22 | [[Dummy new] test]; 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /Test/minRep1.mm: -------------------------------------------------------------------------------- 1 | #import "Test.h" 2 | 3 | #import "minRep1.h" 4 | 5 | #import "stdio.h" 6 | 7 | @implementation MinRep1 8 | 9 | - (void)poke 10 | { 11 | printf("Poking from minRep1\n"); 12 | poke_objcxx(); 13 | } 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Test/msgInterpose.m: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "Test.h" 5 | #include "../objc/hooks.h" 6 | #include "../objc/capabilities.h" 7 | 8 | 9 | int count; 10 | static const int loops = 50000; 11 | static const int depth = 42; 12 | static const int calls = loops * (depth+1); 13 | static int d = depth; 14 | Class TestCls; 15 | int tracecount; 16 | 17 | @implementation Test (Nothing) 18 | + nothing 19 | { 20 | count++; 21 | if (d > 0) 22 | { 23 | d--; 24 | [self nothing]; 25 | d++; 26 | } 27 | return 0; 28 | } 29 | @end 30 | __thread IMP real; 31 | 32 | static int interposecount; 33 | id interpose(id self, SEL _cmd) { 34 | interposecount++; 35 | return real(self, _cmd); 36 | } 37 | 38 | //IMP hook(id object, SEL selector, IMP method, int isReturn, void *wordReturn) { tracecount++; return (IMP)logExit; } 39 | IMP hook(id object, SEL selector, IMP method, int isReturn, void *wordReturn) { tracecount++; real = method; return (IMP)0; } 40 | IMP hook0(id object, SEL selector, IMP method, int isReturn, void *wordReturn) { tracecount++; real = method; return (IMP)1; } 41 | IMP hook1(id object, SEL selector, IMP method, int isReturn, void *wordReturn) { tracecount++; real = method; return (IMP)interpose; } 42 | 43 | int main(void) 44 | { 45 | if (!objc_test_capability(OBJC_CAP_TRACING)) 46 | { 47 | fprintf(stderr, "Tracing support not compiled into runtime\n"); 48 | return 0; 49 | } 50 | TestCls = objc_getClass("Test"); 51 | objc_registerTracingHook(@selector(nothing), hook); 52 | interposecount = 0; 53 | count = 0; 54 | tracecount = 0; 55 | for (int i=0 ; i 2 | #include 3 | #include "../objc/runtime.h" 4 | #include "../objc/hooks.h" 5 | 6 | // Pass and return for type size <= 8 bytes. 7 | struct S1 { 8 | int a[2]; 9 | }; 10 | 11 | // Pass and return hfa <= 8 bytes 12 | struct F1 { 13 | float a[2]; 14 | }; 15 | 16 | // Pass and return type size <= 16 bytes 17 | struct S2 { 18 | int a[4]; 19 | }; 20 | 21 | // Pass and return for type size > 16 bytes. 22 | struct S3 { 23 | int a[5]; 24 | }; 25 | 26 | // Pass and return aggregate (of size < 16 bytes) with non-trivial destructor. 27 | // Sret and inreg: Returned in x0 28 | struct S4 { 29 | int a[3]; 30 | ~S4(); 31 | }; 32 | S4::~S4() { 33 | } 34 | 35 | // Pass and return an object with a user-provided constructor (passed directly, 36 | // returned indirectly) 37 | struct S5 { 38 | S5(); 39 | int x; 40 | }; 41 | S5::S5() { 42 | x = 42; 43 | } 44 | 45 | Class TestCls; 46 | #ifdef __has_attribute 47 | #if __has_attribute(objc_root_class) 48 | __attribute__((objc_root_class)) 49 | #endif 50 | #endif 51 | @interface MsgTest { id isa; } @end 52 | @implementation MsgTest 53 | + (S1) smallS1 { 54 | assert(TestCls == self); 55 | assert(strcmp("smallS1", sel_getName(_cmd)) == 0); 56 | 57 | S1 x; 58 | x.a[0] = 0; 59 | x.a[1] = 1; 60 | return x; 61 | 62 | } 63 | + (F1) smallF1 { 64 | assert(TestCls == self); 65 | assert(strcmp("smallF1", sel_getName(_cmd)) == 0); 66 | 67 | F1 x; 68 | x.a[0] = 0.2f; 69 | x.a[1] = 0.5f; 70 | return x; 71 | } 72 | + (S2) smallS2 { 73 | assert(TestCls == self); 74 | assert(strcmp("smallS2", sel_getName(_cmd)) == 0); 75 | 76 | S2 x; 77 | for (int i = 0; i < 4; i++) { 78 | x.a[i] = i; 79 | } 80 | return x; 81 | } 82 | + (S3) stretS3 { 83 | assert(TestCls == self); 84 | assert(strcmp("stretS3", sel_getName(_cmd)) == 0); 85 | 86 | S3 x; 87 | for (int i = 0; i < 5; i++) { 88 | x.a[i] = i; 89 | } 90 | return x; 91 | } 92 | + (S4) stretInRegS4 { 93 | assert(TestCls == self); 94 | assert(strcmp("stretInRegS4", sel_getName(_cmd)) == 0); 95 | 96 | S4 x; 97 | for (int i = 0; i < 3; i++) { 98 | x.a[i] = i; 99 | } 100 | return x; 101 | } 102 | + (S5) stretInRegS5 { 103 | assert(TestCls == self); 104 | assert(strcmp("stretInRegS5", sel_getName(_cmd)) == 0); 105 | 106 | return S5(); 107 | } 108 | @end 109 | 110 | int main(int argc, char *argv[]) { 111 | #ifdef __GNUSTEP_MSGSEND__ 112 | TestCls = objc_getClass("MsgTest"); 113 | 114 | // Returned in x0 115 | S1 ret = ((S1(*)(id, SEL))objc_msgSend)(TestCls, @selector(smallS1)); 116 | assert(ret.a[0] == 0); 117 | assert(ret.a[1] == 1); 118 | 119 | F1 retF1 = ((F1(*)(id, SEL))objc_msgSend)(TestCls, @selector(smallF1)); 120 | assert(retF1.a[0] == 0.2f); 121 | assert(retF1.a[1] == 0.5f); 122 | 123 | // Returned in x0 and x1 124 | S2 ret2 = ((S2(*)(id, SEL))objc_msgSend)(TestCls, @selector(smallS2)); 125 | for (int i = 0; i < 4; i++) { 126 | assert(ret2.a[i] == i); 127 | } 128 | 129 | // Indirect result register x8 used 130 | S3 ret3 = ((S3(*)(id, SEL))objc_msgSend_stret)(TestCls, @selector(stretS3)); 131 | for (int i = 0; i < 5; i++) { 132 | assert(ret3.a[i] == i); 133 | } 134 | 135 | // Stret with inreg. Returned in x0. 136 | S4 ret4 = ((S4(*)(id, SEL))objc_msgSend_stret2)(TestCls, @selector(stretInRegS4)); 137 | for (int i = 0; i < 3; i++) { 138 | assert(ret4.a[i] == i); 139 | } 140 | 141 | // Stret with inreg. Returned in x0. 142 | S5 ret5 = ((S5(*)(id, SEL))objc_msgSend_stret2)(TestCls, @selector(stretInRegS5)); 143 | assert(ret5.x == 42); 144 | 145 | return 0; 146 | #endif // __GNUSTEP_MSGSEND__ 147 | return 77; 148 | } 149 | -------------------------------------------------------------------------------- /Test/zeroSizedIVar.m: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "Test.h" 4 | 5 | 6 | typedef uintptr_t NSUInteger; 7 | 8 | @interface NSArray : Test 9 | { 10 | NSUInteger count; 11 | id objects[0]; 12 | } 13 | @end 14 | 15 | @implementation NSArray @end 16 | 17 | @interface BitfieldTest : Test 18 | { 19 | BOOL flag1:1; 20 | BOOL flag2:1; 21 | BOOL flag3:1; 22 | } 23 | @end 24 | 25 | @implementation BitfieldTest @end 26 | 27 | @interface BitfieldTest2 : Test 28 | { 29 | BOOL flag1:1; 30 | BOOL flag2:1; 31 | BOOL flag3:1; 32 | int x; 33 | } 34 | @end 35 | 36 | @implementation BitfieldTest2 @end 37 | 38 | 39 | int main() 40 | { 41 | Class nsarray = objc_getClass("NSArray"); 42 | assert(nsarray); 43 | assert(class_getInstanceSize(nsarray) == (sizeof(Class) + sizeof(NSUInteger))); 44 | Ivar count = class_getInstanceVariable(nsarray, "count"); 45 | assert(ivar_getOffset(count) == sizeof(id)); 46 | 47 | Class bitfield = objc_getClass("BitfieldTest"); 48 | assert(bitfield); 49 | Ivar flag1 = class_getInstanceVariable(bitfield, "flag1"); 50 | assert(flag1); 51 | assert(ivar_getOffset(flag1) == sizeof(id)); 52 | Ivar flag2 = class_getInstanceVariable(bitfield, "flag2"); 53 | assert(flag2); 54 | assert(ivar_getOffset(flag2) == sizeof(id)); 55 | Ivar flag3 = class_getInstanceVariable(bitfield, "flag3"); 56 | assert(flag3); 57 | assert(ivar_getOffset(flag3) == sizeof(id)); 58 | assert(ivar_getOffset(flag3) + sizeof(BOOL) <= class_getInstanceSize(bitfield)); 59 | 60 | bitfield = objc_getClass("BitfieldTest2"); 61 | flag1 = class_getInstanceVariable(bitfield, "flag1"); 62 | flag3 = class_getInstanceVariable(bitfield, "flag3"); 63 | Ivar x = class_getInstanceVariable(bitfield, "x"); 64 | assert(ivar_getOffset(flag1) == ivar_getOffset(flag3)); 65 | assert(ivar_getOffset(x) > ivar_getOffset(flag3)); 66 | assert(ivar_getOffset(x) + sizeof(int) <= class_getInstanceSize(bitfield)); 67 | } 68 | 69 | -------------------------------------------------------------------------------- /abi_version.c: -------------------------------------------------------------------------------- 1 | #include "visibility.h" 2 | #include "objc/runtime.h" 3 | #include "module.h" 4 | #include "gc_ops.h" 5 | #include 6 | #include 7 | #include 8 | 9 | /** 10 | * The smallest ABI version number of loaded modules. 11 | */ 12 | static unsigned long min_loaded_version; 13 | /** 14 | * The largest ABI version number of loaded modules. 15 | */ 16 | static unsigned long max_loaded_version; 17 | 18 | /** 19 | * Structure defining the compatibility between Objective-C ABI versions. 20 | */ 21 | struct objc_abi_version 22 | { 23 | /** Version of this ABI. */ 24 | unsigned long version; 25 | /** Lowest ABI version that this is compatible with. */ 26 | unsigned long min_compatible_version; 27 | /** Highest ABI version compatible with this. */ 28 | unsigned long max_compatible_version; 29 | /** Size of the module structure for this ABI version. */ 30 | unsigned long module_size; 31 | }; 32 | 33 | enum 34 | { 35 | gcc_abi = 8, 36 | gnustep_abi = 9, 37 | gc_abi = 10 38 | }; 39 | 40 | /** 41 | * List of supported ABIs. 42 | */ 43 | static struct objc_abi_version known_abis[] = 44 | { 45 | /* GCC ABI. */ 46 | {gcc_abi, gcc_abi, gnustep_abi, sizeof(struct objc_module_abi_8)}, 47 | /* Non-fragile ABI. */ 48 | {gnustep_abi, gcc_abi, gc_abi, sizeof(struct objc_module_abi_8)}, 49 | /* GC ABI. Adds a field describing the GC mode. */ 50 | {gc_abi, gcc_abi, gc_abi, sizeof(struct objc_module_abi_10)} 51 | }; 52 | 53 | static int known_abi_count = 54 | (sizeof(known_abis) / sizeof(struct objc_abi_version)); 55 | 56 | #define FAIL_IF(x, msg) do {\ 57 | if (x)\ 58 | {\ 59 | fprintf(stderr, "Objective-C ABI Error: %s while loading %s\n", msg, module->name);\ 60 | return NO;\ 61 | }\ 62 | } while(0) 63 | 64 | static BOOL endsWith(const char *string, const char *suffix) 65 | { 66 | if (NULL == string) { return NO; } 67 | char *interior = strstr(string, suffix); 68 | return (interior && (strlen(suffix) == strlen(interior))); 69 | } 70 | 71 | PRIVATE BOOL objc_check_abi_version(struct objc_module_abi_8 *module) 72 | { 73 | static int runtime_modules = 5; 74 | // As a quick and ugly hack, skip these three tests for the .m files in the 75 | // runtime. They should (in theory, at least) be aware of the GC mode and 76 | // behave accordingly. 77 | if (runtime_modules > 0) 78 | { 79 | if (endsWith(module->name, "properties.m") || 80 | endsWith(module->name, "associate.m") || 81 | endsWith(module->name, "arc.m") || 82 | endsWith(module->name, "blocks_runtime.m") || 83 | endsWith(module->name, "Protocol2.m")) 84 | { 85 | runtime_modules--; 86 | return YES; 87 | } 88 | } 89 | unsigned long version = module->version; 90 | unsigned long module_size = module->size; 91 | enum objc_gc_mode gc_mode = (version < gc_abi) ? GC_None 92 | : ((struct objc_module_abi_10*)module)->gc_mode; 93 | struct objc_abi_version *v = NULL; 94 | for (int i=0 ; imodule_size != module_size), "Incorrect module size"); 104 | // Only check for ABI compatibility if 105 | if (min_loaded_version > 0) 106 | { 107 | FAIL_IF((v->min_compatible_version > min_loaded_version), 108 | "Loading modules from incompatible ABIs"); 109 | FAIL_IF((v->max_compatible_version < max_loaded_version), 110 | "Loading modules from incompatible ABIs"); 111 | if (min_loaded_version > version) 112 | { 113 | min_loaded_version = version; 114 | } 115 | if (max_loaded_version < version) 116 | { 117 | max_loaded_version = version; 118 | } 119 | } 120 | else 121 | { 122 | min_loaded_version = version; 123 | max_loaded_version = version; 124 | } 125 | 126 | // We can't mix GC_None and GC_Required code, but we can mix any other 127 | // combination 128 | FAIL_IF((gc_mode == GC_Required), "GC code is no longer supported!"); 129 | return YES; 130 | } 131 | -------------------------------------------------------------------------------- /alias.h: -------------------------------------------------------------------------------- 1 | /** Declaration of a helper function for getting class references from aliases. 2 | Copyright (c) 2011 Free Software Foundation, Inc. 3 | 4 | Written by: Niels Grewe 5 | Created: March 2011 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | THE SOFTWARE. 24 | */ 25 | #include "objc/runtime.h" 26 | 27 | OBJC_PUBLIC Class alias_getClass(const char *alias_name); 28 | -------------------------------------------------------------------------------- /alias_table.c: -------------------------------------------------------------------------------- 1 | /** A hash table for mapping compatibility aliases to classes. 2 | Copyright (c) 2011 Free Software Foundation, Inc. 3 | 4 | Written by: Niels Grewe 5 | Created: March 2011 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | THE SOFTWARE. 24 | */ 25 | 26 | #include "visibility.h" 27 | #include "objc/runtime.h" 28 | #include "class.h" 29 | #include "lock.h" 30 | #include "string_hash.h" 31 | 32 | #include 33 | 34 | struct objc_alias 35 | { 36 | const char* name; 37 | Class class; 38 | }; 39 | 40 | typedef struct objc_alias Alias; 41 | 42 | static int alias_compare(const char *name, const Alias alias) 43 | { 44 | return string_compare(name, alias.name); 45 | } 46 | 47 | static int alias_hash(const Alias alias) 48 | { 49 | return string_hash(alias.name); 50 | } 51 | static int alias_is_null(const Alias alias) 52 | { 53 | return alias.name == NULL; 54 | } 55 | static Alias NullAlias; 56 | #define MAP_TABLE_NAME alias_table_internal 57 | #define MAP_TABLE_COMPARE_FUNCTION alias_compare 58 | #define MAP_TABLE_HASH_KEY string_hash 59 | #define MAP_TABLE_HASH_VALUE alias_hash 60 | #define MAP_TABLE_VALUE_TYPE struct objc_alias 61 | #define MAP_TABLE_VALUE_NULL alias_is_null 62 | #define MAP_TABLE_VALUE_PLACEHOLDER NullAlias 63 | 64 | #include "hash_table.h" 65 | 66 | static alias_table_internal_table *alias_table; 67 | 68 | PRIVATE void init_alias_table(void) 69 | { 70 | alias_table_internal_initialize(&alias_table, 128); 71 | } 72 | 73 | 74 | static Alias alias_table_get_safe(const char *alias_name) 75 | { 76 | return alias_table_internal_table_get(alias_table, alias_name); 77 | } 78 | 79 | 80 | OBJC_PUBLIC Class alias_getClass(const char *alias_name) 81 | { 82 | if (NULL == alias_name) 83 | { 84 | return NULL; 85 | } 86 | 87 | Alias alias = alias_table_get_safe(alias_name); 88 | 89 | if (NULL == alias.name) 90 | { 91 | return NULL; 92 | } 93 | 94 | return alias.class; 95 | } 96 | 97 | PRIVATE void alias_table_insert(Alias alias) 98 | { 99 | alias_table_internal_insert(alias_table, alias); 100 | } 101 | 102 | OBJC_PUBLIC BOOL class_registerAlias_np(Class class, const char *alias) 103 | { 104 | if ((NULL == alias) || (NULL == class)) 105 | { 106 | return 0; 107 | } 108 | 109 | class = (Class)objc_getClass(class->name); 110 | 111 | /* 112 | * If there already exists a matching alias, determine whether we the existing 113 | * alias is the correct one. Please note that objc_getClass() goes through the 114 | * alias lookup and will create the alias table if necessary. 115 | */ 116 | Class existingClass = (Class)objc_getClass(alias); 117 | if (NULL != existingClass) 118 | { 119 | /* 120 | * Return YES if the alias has already been registered for this very 121 | * class, and NO if the alias is already used for another class. 122 | */ 123 | return (class == existingClass); 124 | } 125 | Alias newAlias = { strdup(alias), class }; 126 | alias_table_insert(newAlias); 127 | return 1; 128 | } 129 | -------------------------------------------------------------------------------- /asmconstants.h: -------------------------------------------------------------------------------- 1 | #ifdef __LP64__ 2 | #define DTABLE_OFFSET 64 3 | #define SMALLOBJ_BITS 3 4 | #define SHIFT_OFFSET 0 5 | #define DATA_OFFSET 8 6 | #define SLOT_OFFSET 0 7 | #elif defined(_WIN64) 8 | // long is 32 bits on Win64, so struct objc_class is smaller. All other offsets are the same. 9 | #define DTABLE_OFFSET 56 10 | #define SMALLOBJ_BITS 3 11 | #define SHIFT_OFFSET 0 12 | #define DATA_OFFSET 8 13 | #define SLOT_OFFSET 0 14 | #else 15 | #define DTABLE_OFFSET 32 16 | #define SMALLOBJ_BITS 1 17 | #define SHIFT_OFFSET 0 18 | #define DATA_OFFSET 8 19 | #define SLOT_OFFSET 0 20 | #endif 21 | #define SMALLOBJ_MASK ((1< 33 | #import 34 | #endif 35 | #include "visibility.h" 36 | 37 | 38 | OBJC_PUBLIC const char *block_getType_np(const void *b) 39 | { 40 | return _Block_signature((void*)b); 41 | } 42 | 43 | /** 44 | * Returns the block pointer, or NULL if the block is already 45 | * being deallocated. The implementation does not employ atomic 46 | * operations, so this function must only be called by the ARC 47 | * subsystem after obtaining the weak-reference lock. 48 | */ 49 | PRIVATE void* block_load_weak(void *block) 50 | { 51 | struct Block_layout *self = block; 52 | #ifdef EMBEDDED_BLOCKS_RUNTIME 53 | return (self->reserved) > 0 ? block : 0; 54 | #else 55 | return (self->flags) & BLOCK_REFCOUNT_MASK ? block : 0; 56 | #endif 57 | } 58 | -------------------------------------------------------------------------------- /buffer.h: -------------------------------------------------------------------------------- 1 | /** 2 | * buffer.h defines a simple dynamic array that is used to store temporary 3 | * values for later processing. Define BUFFER_TYPE before including this file. 4 | */ 5 | 6 | #include 7 | 8 | #define BUFFER_SIZE 128 9 | static BUFFER_TYPE buffered_object_buffer[BUFFER_SIZE]; 10 | static BUFFER_TYPE *buffered_object_overflow; 11 | static int buffered_objects; 12 | static int buffered_object_overflow_space; 13 | 14 | static void set_buffered_object_at_index(BUFFER_TYPE cat, unsigned int i) 15 | { 16 | if (i < BUFFER_SIZE) 17 | { 18 | buffered_object_buffer[i] = cat; 19 | } 20 | else 21 | { 22 | i -= BUFFER_SIZE; 23 | if (NULL == buffered_object_overflow) 24 | { 25 | buffered_object_overflow = 26 | calloc(BUFFER_SIZE, sizeof(BUFFER_TYPE)); 27 | buffered_object_overflow_space = BUFFER_SIZE; 28 | } 29 | while (i >= buffered_object_overflow_space) 30 | { 31 | buffered_object_overflow_space <<= 1; 32 | buffered_object_overflow = realloc(buffered_object_overflow, 33 | buffered_object_overflow_space * sizeof(BUFFER_TYPE)); 34 | } 35 | buffered_object_overflow[i] = cat; 36 | } 37 | } 38 | 39 | static BUFFER_TYPE buffered_object_at_index(unsigned int i) 40 | { 41 | if (i 3 | 4 | /** 5 | * Bitmask of all of the capabilities compiled into this version of the 6 | * runtime. 7 | */ 8 | static const int32_t caps = 9 | (1<= 32) { return 0; } 40 | if (caps & (1< 2 | #include "objc/runtime.h" 3 | #include "visibility.h" 4 | #include "loader.h" 5 | #include "dtable.h" 6 | #include "properties.h" 7 | 8 | #define BUFFER_TYPE struct objc_category * 9 | #include "buffer.h" 10 | 11 | void objc_send_load_message(Class class); 12 | 13 | static void register_methods(struct objc_class *cls, struct objc_method_list *l) 14 | { 15 | if (NULL == l) { return; } 16 | 17 | // Add the method list at the head of the list of lists. 18 | l->next = cls->methods; 19 | cls->methods = l; 20 | // Update the dtable to catch the new methods, if the dtable has been 21 | // created (don't bother creating dtables for classes when categories are 22 | // loaded if the class hasn't received any messages yet. 23 | if (classHasDtable(cls)) 24 | { 25 | add_method_list_to_class(cls, l); 26 | } 27 | } 28 | 29 | static void load_category(struct objc_category *cat, struct objc_class *class) 30 | { 31 | register_methods(class, cat->instance_methods); 32 | register_methods(class->isa, cat->class_methods); 33 | //fprintf(stderr, "Loading %s (%s)\n", cat->class_name, cat->name); 34 | 35 | if (cat->protocols) 36 | { 37 | objc_init_protocols(cat->protocols); 38 | cat->protocols->next = class->protocols; 39 | class->protocols = cat->protocols; 40 | } 41 | if (cat->properties) 42 | { 43 | cat->properties->next = class->properties; 44 | class->properties = cat->properties; 45 | } 46 | if (cat->class_properties) 47 | { 48 | cat->class_properties->next = class->isa->properties; 49 | class->isa->properties = cat->class_properties; 50 | } 51 | } 52 | 53 | static BOOL try_load_category(struct objc_category *cat) 54 | { 55 | Class class = (Class)objc_getClass(cat->class_name); 56 | //fprintf(stderr, "Trying to load %s (%s)\n", cat->class_name, cat->name); 57 | if (Nil != class) 58 | { 59 | load_category(cat, class); 60 | return YES; 61 | } 62 | //fprintf(stderr, "waiting to load %s (%s)\n", cat->class_name, cat->name); 63 | return NO; 64 | } 65 | 66 | /** 67 | * Attaches a category to its class, if the class is already loaded. Buffers 68 | * it for future resolution if not. 69 | */ 70 | PRIVATE void objc_try_load_category(struct objc_category *cat) 71 | { 72 | if (!try_load_category(cat)) 73 | { 74 | set_buffered_object_at_index(cat, buffered_objects++); 75 | } 76 | } 77 | 78 | PRIVATE void objc_load_buffered_categories(void) 79 | { 80 | BOOL shouldReshuffle = NO; 81 | 82 | for (unsigned i=0 ; i 11 | 12 | OBJC_PUBLIC 13 | id 14 | objc_alloc(Class cls) 15 | { 16 | if (UNLIKELY(cls == nil)) 17 | { 18 | return nil; 19 | } 20 | if (UNLIKELY(!objc_test_class_flag(cls->isa, objc_class_flag_initialized))) 21 | { 22 | objc_send_initialize(cls); 23 | } 24 | if (objc_test_class_flag(cls->isa, objc_class_flag_fast_alloc_init)) 25 | { 26 | return class_createInstance(cls, 0); 27 | } 28 | return [cls alloc]; 29 | } 30 | 31 | /** 32 | * Equivalent to [cls allocWithZone: null]. If there's a fast path opt-in, then this skips the message send. 33 | */ 34 | OBJC_PUBLIC 35 | id 36 | objc_allocWithZone(Class cls) 37 | { 38 | if (UNLIKELY(cls == nil)) 39 | { 40 | return nil; 41 | } 42 | if (UNLIKELY(!objc_test_class_flag(cls->isa, objc_class_flag_initialized))) 43 | { 44 | objc_send_initialize(cls); 45 | } 46 | if (objc_test_class_flag(cls->isa, objc_class_flag_fast_alloc_init)) 47 | { 48 | return class_createInstance(cls, 0); 49 | } 50 | return [cls allocWithZone: NULL]; 51 | } 52 | 53 | /** 54 | * Equivalent to [[cls alloc] init]. If there's a fast path opt-in, then this 55 | * skips the message send. 56 | */ 57 | OBJC_PUBLIC 58 | id 59 | objc_alloc_init(Class cls) 60 | { 61 | if (UNLIKELY(cls == nil)) 62 | { 63 | return nil; 64 | } 65 | id instance = objc_alloc(cls); 66 | // If +alloc was overwritten, it is not guaranteed that it returns 67 | // an instance of cls. 68 | cls = classForObject(instance); 69 | if (objc_test_class_flag(cls, objc_class_flag_fast_alloc_init)) 70 | { 71 | return instance; 72 | } 73 | return [instance init]; 74 | } 75 | -------------------------------------------------------------------------------- /gc_none.c: -------------------------------------------------------------------------------- 1 | #include "visibility.h" 2 | #include "objc/runtime.h" 3 | #include "gc_ops.h" 4 | #include "class.h" 5 | #include 6 | #include 7 | #include 8 | 9 | static id allocate_class(Class cls, size_t extraBytes) 10 | { 11 | size_t size = cls->instance_size + extraBytes + sizeof(intptr_t); 12 | intptr_t *addr = 13 | #ifdef _WIN32 14 | // Malloc on Windows doesn't guarantee 32-byte alignment, but we 15 | // require this for any class that may contain vectors 16 | _aligned_malloc(size, 32); 17 | memset(addr, 0, size); 18 | #else 19 | calloc(size, 1); 20 | #endif 21 | return (id)(addr + 1); 22 | } 23 | 24 | static void free_object(id obj) 25 | { 26 | #ifdef _WIN32 27 | _aligned_free((void*)(((intptr_t*)obj) - 1)); 28 | #else 29 | free((void*)(((intptr_t*)obj) - 1)); 30 | #endif 31 | } 32 | 33 | static void *alloc(size_t size) 34 | { 35 | return calloc(size, 1); 36 | } 37 | 38 | void objc_registerThreadWithCollector(void) {} 39 | void objc_unregisterThreadWithCollector(void) {} 40 | void objc_assertRegisteredThreadWithCollector() {} 41 | 42 | PRIVATE struct gc_ops gc_ops_none = 43 | { 44 | .allocate_class = allocate_class, 45 | .free_object = free_object, 46 | .malloc = alloc, 47 | .free = free 48 | }; 49 | PRIVATE struct gc_ops *gc = &gc_ops_none; 50 | 51 | void objc_set_collection_threshold(size_t threshold) {} 52 | void objc_set_collection_ratio(size_t ratio) {} 53 | void objc_collect(unsigned long options) {} 54 | BOOL objc_collectingEnabled(void) { return NO; } 55 | BOOL objc_atomicCompareAndSwapPtr(id predicate, id replacement, volatile id *objectLocation) 56 | { 57 | return __sync_bool_compare_and_swap(objectLocation, predicate, replacement); 58 | } 59 | BOOL objc_atomicCompareAndSwapPtrBarrier(id predicate, id replacement, volatile id *objectLocation) 60 | { 61 | return __sync_bool_compare_and_swap(objectLocation, predicate, replacement); 62 | } 63 | 64 | BOOL objc_atomicCompareAndSwapGlobal(id predicate, id replacement, volatile id *objectLocation) 65 | { 66 | return objc_atomicCompareAndSwapPtr(predicate, replacement, objectLocation); 67 | } 68 | BOOL objc_atomicCompareAndSwapGlobalBarrier(id predicate, id replacement, volatile id *objectLocation) 69 | { 70 | return objc_atomicCompareAndSwapPtr(predicate, replacement, objectLocation); 71 | } 72 | BOOL objc_atomicCompareAndSwapInstanceVariable(id predicate, id replacement, volatile id *objectLocation) 73 | { 74 | return objc_atomicCompareAndSwapPtr(predicate, replacement, objectLocation); 75 | } 76 | BOOL objc_atomicCompareAndSwapInstanceVariableBarrier(id predicate, id replacement, volatile id *objectLocation) 77 | { 78 | return objc_atomicCompareAndSwapPtr(predicate, replacement, objectLocation); 79 | } 80 | 81 | id objc_assign_strongCast(id val, id *ptr) 82 | { 83 | *ptr = val; 84 | return val; 85 | } 86 | 87 | id objc_assign_global(id val, id *ptr) 88 | { 89 | *ptr = val; 90 | return val; 91 | } 92 | 93 | id objc_assign_ivar(id val, id dest, ptrdiff_t offset) 94 | { 95 | *(id*)((char*)dest+offset) = val; 96 | return val; 97 | } 98 | 99 | void *objc_memmove_collectable(void *dst, const void *src, size_t size) 100 | { 101 | return memmove(dst, src, size); 102 | } 103 | id objc_read_weak(id *location) 104 | { 105 | return *location; 106 | } 107 | id objc_assign_weak(id value, id *location) 108 | { 109 | *location = value; 110 | return value; 111 | } 112 | id objc_allocate_object(Class cls, int extra) 113 | { 114 | return class_createInstance(cls, extra); 115 | } 116 | 117 | BOOL objc_collecting_enabled(void) { return NO; } 118 | void objc_startCollectorThread(void) {} 119 | void objc_clear_stack(unsigned long options) {} 120 | BOOL objc_is_finalized(void *ptr) { return NO; } 121 | void objc_finalizeOnMainThread(Class cls) {} 122 | -------------------------------------------------------------------------------- /gc_ops.h: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Garbage collection operations. 4 | */ 5 | struct gc_ops 6 | { 7 | /** 8 | * Initialises this collector. 9 | */ 10 | void (*init)(void); 11 | /** 12 | * Allocates enough space for a class, followed by some extra bytes. 13 | */ 14 | id (*allocate_class)(Class, size_t); 15 | /** 16 | * Frees an object. 17 | */ 18 | void (*free_object)(id); 19 | /** 20 | * Allocates some memory that can be used to store pointers. This must be 21 | * used instead of malloc() for internal data structures that will store 22 | * pointers passed in from outside. The function is expected to zero the 23 | * memory that it returns. 24 | */ 25 | void* (*malloc)(size_t); 26 | /** 27 | * Frees some memory that was previously used to store pointers. 28 | */ 29 | void (*free)(void*); 30 | }; 31 | 32 | /** 33 | * The mode for garbage collection 34 | */ 35 | enum objc_gc_mode 36 | { 37 | /** This module neither uses, nor supports, garbage collection. */ 38 | GC_None = 0, 39 | /** 40 | * This module uses garbage collection, but also sends retain / release 41 | * messages. It can be used with or without GC. 42 | */ 43 | GC_Optional = 1, 44 | /** 45 | * This module expects garbage collection and will break without it. 46 | */ 47 | GC_Required = 2, 48 | /** 49 | * This module was compiled with automatic reference counting. This 50 | * guarantees the use of the non-fragile ABI and means that we could 51 | * potentially support GC, although we don't currently. 52 | */ 53 | GC_ARC = 3 54 | }; 55 | 56 | /** 57 | * The current set of garbage collector operations to use. 58 | */ 59 | extern struct gc_ops *gc; 60 | 61 | -------------------------------------------------------------------------------- /hooks.c: -------------------------------------------------------------------------------- 1 | #include "objc/runtime.h" 2 | #define OBJC_HOOK OBJC_PUBLIC 3 | #include "objc/hooks.h" 4 | -------------------------------------------------------------------------------- /legacy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "visibility.h" 3 | #include "ivar.h" 4 | #include "class.h" 5 | #include "category.h" 6 | #include "protocol.h" 7 | 8 | PRIVATE Class objc_upgrade_class(struct objc_class_gsv1 *oldClass); 9 | PRIVATE struct objc_category *objc_upgrade_category(struct objc_category_gcc *); 10 | 11 | PRIVATE struct objc_class_gsv1* objc_legacy_class_for_class(Class); 12 | 13 | PRIVATE struct objc_protocol *objc_upgrade_protocol_gcc(struct objc_protocol_gcc*); 14 | PRIVATE struct objc_protocol *objc_upgrade_protocol_gsv1(struct objc_protocol_gsv1*); 15 | 16 | -------------------------------------------------------------------------------- /legacy_malloc.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void *valloc(size_t); 4 | 5 | // Stubs that just call the libc implementations when you call these. 6 | 7 | void *objc_malloc(size_t size) 8 | { 9 | return malloc(size); 10 | } 11 | 12 | void *objc_atomic_malloc(size_t size) 13 | { 14 | return malloc(size); 15 | } 16 | 17 | #ifdef __MINGW32__ 18 | void *objc_valloc(size_t size) 19 | { 20 | return malloc(size); 21 | } 22 | #else 23 | void *objc_valloc(size_t size) 24 | { 25 | return valloc(size); 26 | } 27 | #endif 28 | 29 | void *objc_realloc(void *mem, size_t size) 30 | { 31 | return realloc(mem, size); 32 | } 33 | 34 | void * objc_calloc(size_t nelem, size_t size) 35 | { 36 | return calloc(nelem, size); 37 | } 38 | 39 | void objc_free(void *mem) 40 | { 41 | free(mem); 42 | } 43 | 44 | -------------------------------------------------------------------------------- /libobjc.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@PC_INSTALL_PREFIX@ 2 | exec_prefix=${prefix} 3 | libdir=${exec_prefix}/@LIB_INSTALL_PATH@ 4 | includedir=${prefix}/@HEADER_INSTALL_PATH@ 5 | 6 | Name: libobjc 7 | Description: GNUstep Objective-C runtime library 8 | Version: @CPACK_PACKAGE_VERSION_MAJOR@.@CPACK_PACKAGE_VERSION_MINOR@.@CPACK_PACKAGE_VERSION_PATCH@ 9 | 10 | Cflags: -I${includedir} 11 | Libs: -L${libdir} -lobjc 12 | @PC_LIBS_PRIVATE@ 13 | -------------------------------------------------------------------------------- /loader.h: -------------------------------------------------------------------------------- 1 | #ifndef __OBJC_LOADER_H_INCLUDED 2 | #define __OBJC_LOADER_H_INCLUDED 3 | #include "category.h" 4 | #include "method.h" 5 | #include "module.h" 6 | #include "class.h" 7 | #include "protocol.h" 8 | 9 | /** 10 | * Checks whether it is safe to load a module with the specified version and 11 | * module size. This depends on whether another module with an incompatible 12 | * ABI has already been loaded. 13 | */ 14 | BOOL objc_check_abi_version(struct objc_module_abi_8 *module); 15 | /** 16 | * Initializes a protocol list, uniquing the protocols in the list. 17 | */ 18 | void objc_init_protocols(struct objc_protocol_list *protocols); 19 | /** 20 | * Registers a set of selectors from a method list. 21 | */ 22 | void objc_register_selectors_from_list(struct objc_method_list *l); 23 | /** 24 | * Register all of the (unregistered) selectors that are used in a class. 25 | */ 26 | void objc_register_selectors_from_class(Class class); 27 | /** 28 | * Registers all of the selectors in an array. 29 | */ 30 | void objc_register_selector_array(SEL selectors, unsigned long count); 31 | /** 32 | * Loads a class into the runtime system. If possible, the class is resolved 33 | * (inserted into the class tree) immediately. If its superclass is not yet 34 | * resolved, it is enqueued for later resolution. 35 | */ 36 | void objc_load_class(struct objc_class *class); 37 | /** 38 | * Resolves classes that have not yet been resolved, if their superclasses have 39 | * subsequently been loaded. 40 | */ 41 | void objc_resolve_class_links(void); 42 | /** 43 | * Attaches a category to its class, if the class is already loaded. Buffers 44 | * it for future resolution if not. 45 | */ 46 | void objc_try_load_category(struct objc_category *cat); 47 | /** 48 | * Tries to load all of the categories that could not previously be loaded 49 | * because their classes were not yet loaded. 50 | */ 51 | void objc_load_buffered_categories(void); 52 | /** 53 | * Updates the dispatch table for a class. 54 | */ 55 | void objc_update_dtable_for_class(Class cls); 56 | /** 57 | * Initialises a list of static object instances belonging to the same class if 58 | * possible, or defers initialisation until the class has been loaded it not. 59 | */ 60 | void objc_init_statics(struct objc_static_instance_list *statics); 61 | /** 62 | * Tries again to initialise static instances which could not be initialised 63 | * earlier. 64 | */ 65 | void objc_init_buffered_statics(void); 66 | 67 | /** 68 | * Initialise built-in classes (Object and Protocol). This must be called 69 | * after `init_class_tables`. 70 | */ 71 | void init_builtin_classes(void); 72 | 73 | /** 74 | * Initialise the aliases table. 75 | */ 76 | void init_alias_table(void); 77 | 78 | /** 79 | * Initialise the automatic reference counting system. 80 | */ 81 | void init_arc(void); 82 | 83 | /** 84 | * Initialise the class tables. 85 | */ 86 | void init_class_tables(void); 87 | 88 | /** 89 | * Initialise the dispatch table machinery. 90 | */ 91 | void init_dispatch_tables(void); 92 | 93 | /** 94 | * Initialise the protocol tables. 95 | */ 96 | void init_protocol_table(void); 97 | 98 | /** 99 | * Initialise the selector tables. 100 | */ 101 | void init_selector_tables(void); 102 | 103 | /** 104 | * Initialise the trampolines for using blocks as methods. 105 | */ 106 | void init_trampolines(void); 107 | 108 | /** 109 | * Send +load messages to a class if required. 110 | */ 111 | void objc_send_load_message(Class cls); 112 | 113 | /** 114 | * Resolve a class (populate its superclass and sibling class links). Returns 115 | * YES if the class can be resolved, NO otherwise. Classes cannot be resolved 116 | * unless their superclasses have all been resolved. 117 | */ 118 | BOOL objc_resolve_class(Class cls); 119 | 120 | /** 121 | * Initialise the block classes. 122 | */ 123 | void init_early_blocks(void); 124 | 125 | 126 | #endif //__OBJC_LOADER_H_INCLUDED 127 | -------------------------------------------------------------------------------- /lock.h: -------------------------------------------------------------------------------- 1 | /** 2 | * libobjc requires recursive mutexes. These are delegated to the underlying 3 | * threading implementation. This file contains a VERY thin wrapper over the 4 | * Windows and POSIX mutex APIs. 5 | */ 6 | 7 | #ifndef __LIBOBJC_LOCK_H_INCLUDED__ 8 | #define __LIBOBJC_LOCK_H_INCLUDED__ 9 | #ifdef _WIN32 10 | # include "safewindows.h" 11 | typedef CRITICAL_SECTION mutex_t; 12 | # define INIT_LOCK(x) InitializeCriticalSection(&(x)) 13 | # define LOCK(x) EnterCriticalSection(x) 14 | # define UNLOCK(x) LeaveCriticalSection(x) 15 | # define DESTROY_LOCK(x) DeleteCriticalSection(x) 16 | #else 17 | 18 | # include 19 | 20 | typedef pthread_mutex_t mutex_t; 21 | // If this pthread implementation has a static initializer for recursive 22 | // mutexes, use that, otherwise fall back to the portable version 23 | # ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP 24 | # define INIT_LOCK(x) x = (pthread_mutex_t)PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP 25 | # elif defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER) 26 | # define INIT_LOCK(x) x = (pthread_mutex_t)PTHREAD_RECURSIVE_MUTEX_INITIALIZER 27 | # else 28 | # define INIT_LOCK(x) init_recursive_mutex(&(x)) 29 | 30 | static inline void init_recursive_mutex(pthread_mutex_t *x) 31 | { 32 | pthread_mutexattr_t recursiveAttributes; 33 | pthread_mutexattr_init(&recursiveAttributes); 34 | pthread_mutexattr_settype(&recursiveAttributes, PTHREAD_MUTEX_RECURSIVE); 35 | pthread_mutex_init(x, &recursiveAttributes); 36 | pthread_mutexattr_destroy(&recursiveAttributes); 37 | } 38 | # endif 39 | 40 | # define LOCK(x) pthread_mutex_lock(x) 41 | # define UNLOCK(x) pthread_mutex_unlock(x) 42 | # define DESTROY_LOCK(x) pthread_mutex_destroy(x) 43 | #endif 44 | 45 | __attribute__((unused)) static void objc_release_lock(void *x) 46 | { 47 | mutex_t *lock = *(mutex_t**)x; 48 | UNLOCK(lock); 49 | } 50 | /** 51 | * Concatenate strings during macro expansion. 52 | */ 53 | #define LOCK_HOLDERN_NAME_CAT(x, y) x ## y 54 | /** 55 | * Concatenate string with unique variable during macro expansion. 56 | */ 57 | #define LOCK_HOLDER_NAME_COUNTER(x, y) LOCK_HOLDERN_NAME_CAT(x, y) 58 | /** 59 | * Create a unique name for a lock holder variable 60 | */ 61 | #define LOCK_HOLDER_NAME(x) LOCK_HOLDER_NAME_COUNTER(x, __COUNTER__) 62 | 63 | /** 64 | * Acquires the lock and automatically releases it at the end of the current 65 | * scope. 66 | */ 67 | #define LOCK_FOR_SCOPE(lock) \ 68 | __attribute__((cleanup(objc_release_lock)))\ 69 | __attribute__((unused)) mutex_t *LOCK_HOLDER_NAME(lock_pointer) = lock;\ 70 | LOCK(lock) 71 | 72 | /** 73 | * The global runtime mutex. 74 | */ 75 | extern mutex_t runtime_mutex; 76 | 77 | #define LOCK_RUNTIME() LOCK(&runtime_mutex) 78 | #define UNLOCK_RUNTIME() UNLOCK(&runtime_mutex) 79 | #define LOCK_RUNTIME_FOR_SCOPE() LOCK_FOR_SCOPE(&runtime_mutex) 80 | 81 | #ifdef __cplusplus 82 | /** 83 | * C++ wrapper around our mutex, for use with std::lock_guard and friends. 84 | */ 85 | class RecursiveMutex 86 | { 87 | /// The underlying mutex 88 | mutex_t mutex; 89 | 90 | public: 91 | /** 92 | * Explicit initialisation of the underlying lock, so that this can be a 93 | * global. 94 | */ 95 | void init() 96 | { 97 | INIT_LOCK(mutex); 98 | } 99 | 100 | /// Acquire the lock. 101 | void lock() 102 | { 103 | LOCK(&mutex); 104 | } 105 | 106 | /// Release the lock. 107 | void unlock() 108 | { 109 | UNLOCK(&mutex); 110 | } 111 | }; 112 | #endif 113 | 114 | #endif // __LIBOBJC_LOCK_H_INCLUDED__ 115 | -------------------------------------------------------------------------------- /method.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | /** 5 | * Metadata structure describing a method. 6 | */ 7 | // begin: objc_method 8 | struct objc_method 9 | { 10 | /** 11 | * A pointer to the function implementing this method. 12 | */ 13 | IMP imp; 14 | /** 15 | * Selector used to send messages to this method. 16 | */ 17 | SEL selector; 18 | /** 19 | * The extended type encoding for this method. 20 | */ 21 | const char *types; 22 | }; 23 | // end: objc_method 24 | 25 | struct objc_method_gcc 26 | { 27 | /** 28 | * Selector used to send messages to this method. The type encoding of 29 | * this method should match the types field. 30 | */ 31 | SEL selector; 32 | /** 33 | * The type encoding for this selector. Used only for introspection, and 34 | * only required because of the stupid selector handling in the old GNU 35 | * runtime. In future, this field may be reused for something else. 36 | */ 37 | const char *types; 38 | /** 39 | * A pointer to the function implementing this method. 40 | */ 41 | IMP imp; 42 | }; 43 | 44 | /** 45 | * Method list. Each class or category defines a new one of these and they are 46 | * all chained together in a linked list, with new ones inserted at the head. 47 | * When constructing the dispatch table, methods in the start of the list are 48 | * used in preference to ones at the end. 49 | */ 50 | // begin: objc_method_list 51 | struct objc_method_list 52 | { 53 | /** 54 | * The next group of methods in the list. 55 | */ 56 | struct objc_method_list *next; 57 | /** 58 | * The number of methods in this list. 59 | */ 60 | int count; 61 | /** 62 | * Sze of `struct objc_method`. This allows runtimes downgrading newer 63 | * versions of this structure. 64 | */ 65 | size_t size; 66 | /** 67 | * An array of methods. Note that the actual size of this is count. 68 | */ 69 | struct objc_method methods[]; 70 | }; 71 | // end: objc_method_list 72 | 73 | /** 74 | * Returns a pointer to the method inside the `objc_method` structure. This 75 | * structure is designed to allow the compiler to add other fields without 76 | * breaking the ABI, so although the `methods` field appears to be an array 77 | * of `objc_method` structures, it may be an array of some future version of 78 | * `objc_method` structs, which have fields appended that this version of the 79 | * runtime does not know about. 80 | */ 81 | static inline struct objc_method *method_at_index(struct objc_method_list *l, int i) 82 | { 83 | assert(l->size >= sizeof(struct objc_method)); 84 | return (struct objc_method*)(((char*)l->methods) + (i * l->size)); 85 | } 86 | 87 | /** 88 | * Legacy version of the method list. 89 | */ 90 | struct objc_method_list_gcc 91 | { 92 | /** 93 | * The next group of methods in the list. 94 | */ 95 | struct objc_method_list_gcc *next; 96 | /** 97 | * The number of methods in this list. 98 | */ 99 | int count; 100 | /** 101 | * An array of methods. Note that the actual size of this is count. 102 | */ 103 | struct objc_method_gcc methods[]; 104 | }; 105 | -------------------------------------------------------------------------------- /module.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Defines the module structures. 3 | * 4 | * When defining a new ABI, the 5 | */ 6 | 7 | /** 8 | * The symbol table for a module. This structure references all of the 9 | * Objective-C symbols defined for a module, allowing the runtime to find and 10 | * register them. 11 | */ 12 | struct objc_symbol_table_abi_8 13 | { 14 | /** 15 | * The number of selectors referenced in this module. 16 | */ 17 | unsigned long selector_count; 18 | /** 19 | * An array of selectors used in this compilation unit. SEL is a pointer 20 | * type and this points to the first element in an array of selectors. 21 | */ 22 | SEL selectors; 23 | /** 24 | * The number of classes defined in this module. 25 | */ 26 | unsigned short class_count; 27 | /** 28 | * The number of categories defined in this module. 29 | */ 30 | unsigned short category_count; 31 | /** 32 | * A null-terminated array of pointers to symbols defined in this module. 33 | * This contains class_count pointers to class structures, category_count 34 | * pointers to category structures, and then zero or more pointers to 35 | * static object instances. 36 | * 37 | * Current compilers only use this for constant strings. The runtime 38 | * permits other types. 39 | */ 40 | void *definitions[]; 41 | }; 42 | 43 | /** 44 | * The module structure is passed to the __objc_exec_class function by a 45 | * constructor function when the module is loaded. 46 | * 47 | * When defining a new ABI version, the first two fields in this structure must 48 | * be retained. 49 | */ 50 | struct objc_module_abi_8 51 | { 52 | /** 53 | * The version of the ABI used by this module. This is checked against the 54 | * list of ABIs that the runtime supports, and the list of incompatible 55 | * ABIs. 56 | */ 57 | unsigned long version; 58 | /** 59 | * The size of the module. This is used for sanity checking, to ensure 60 | * that the compiler and runtime's idea of the module size match. 61 | */ 62 | unsigned long size; 63 | /** 64 | * The full path name of the source for this module. Not currently used 65 | * for anything, could be used for debugging in theory, but duplicates 66 | * information available from DWARF data, so probably won't. 67 | */ 68 | const char *name; 69 | /** 70 | * A pointer to the symbol table for this compilation unit. 71 | */ 72 | struct objc_symbol_table_abi_8 *symbol_table; 73 | }; 74 | 75 | struct objc_module_abi_10 76 | { 77 | /** 78 | * Inherited fields from version 8 of the ABI. 79 | */ 80 | struct objc_module_abi_8 old; 81 | /** 82 | * GC mode. GC_Optional code can be mixed with anything, but GC_None code 83 | * can't be mixed with GC_Required code. 84 | */ 85 | int gc_mode; 86 | }; 87 | 88 | /** 89 | * List of static instances of a named class provided in this module. 90 | */ 91 | struct objc_static_instance_list 92 | { 93 | /** 94 | * The name of the class. The isa pointer of all of the instances will be 95 | * set to the class with this name. 96 | */ 97 | char *class_name; 98 | /** 99 | * NULL-terminated array of statically-allocated instances. 100 | */ 101 | id instances[]; 102 | }; 103 | -------------------------------------------------------------------------------- /mutation.m: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "objc/runtime.h" 4 | 5 | // This function is exported as a weak symbol to enable GNUstep or some other 6 | // framework to replace it trivially 7 | OBJC_PUBLIC 8 | void __attribute__((weak)) objc_enumerationMutation(id obj) 9 | { 10 | fprintf(stderr, "Mutation occurred during enumeration."); 11 | abort(); 12 | } 13 | 14 | -------------------------------------------------------------------------------- /nsobject.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Stub declaration of NSObject. Lots of things in the runtime require the 3 | */ 4 | @interface NSObject 5 | -retain; 6 | -copy; 7 | -(void)release; 8 | -autorelease; 9 | -(void)dealloc; 10 | @end 11 | -------------------------------------------------------------------------------- /objc/Availability.h: -------------------------------------------------------------------------------- 1 | #if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__) 2 | #pragma clang system_header 3 | #endif 4 | 5 | #include "objc-visibility.h" 6 | 7 | #ifdef STRICT_MACOS_X 8 | # define OBJC_NONPORTABLE __attribute__((error("Function not supported by the Apple runtime"))) 9 | #else 10 | # define OBJC_NONPORTABLE 11 | #endif 12 | 13 | #if !defined(__DEPRECATE_DIRECT_ACCESS) || defined(__OBJC_LEGACY_GNU_MODE__) || defined(__OBJC_RUNTIME_INTERNAL__) 14 | # define OBJC_DEPRECATED 15 | #else 16 | # define OBJC_DEPRECATED __attribute__((deprecated)) 17 | #endif 18 | 19 | #ifdef ERROR_UNSUPPORTED_RUNTIME_FUNCTIONS 20 | # define OBJC_GNUSTEP_RUNTIME_UNSUPPORTED(x) \ 21 | __attribute__((error(x " not supported by this runtime"))) 22 | #else 23 | # define OBJC_GNUSTEP_RUNTIME_UNSUPPORTED(x) 24 | #endif 25 | 26 | -------------------------------------------------------------------------------- /objc/Object.h: -------------------------------------------------------------------------------- 1 | #if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__) 2 | #pragma clang system_header 3 | #endif 4 | 5 | #include 6 | 7 | @interface Object 8 | { 9 | Class isa; 10 | } 11 | @end 12 | -------------------------------------------------------------------------------- /objc/Protocol.h: -------------------------------------------------------------------------------- 1 | #if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__) 2 | #pragma clang system_header 3 | #endif 4 | 5 | #import "Object.h" 6 | 7 | @interface Protocol : Object @end 8 | -------------------------------------------------------------------------------- /objc/blocks_private.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIBOBJC_BLOCKS_PRIVATE_H_INCLUDED__ 2 | #define __LIBOBJC_BLOCKS_PRIVATE_H_INCLUDED__ 3 | #if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__) 4 | #pragma clang system_header 5 | #endif 6 | #ifdef __cplusplus 7 | #define BLOCKS_EXPORT extern "C" 8 | #else 9 | #define BLOCKS_EXPORT extern 10 | #endif 11 | 12 | #include 13 | #include "Availability.h" 14 | 15 | /* 16 | * This header file exposes some implementation details of the blocks runtime 17 | * that are needed, e.g., by libdispatch. 18 | */ 19 | 20 | 21 | /** 22 | * Block descriptor that contains copy and dispose operations. 23 | */ 24 | struct Block_descriptor 25 | { 26 | /** 27 | * Reserved for future use. Currently always 0. 28 | */ 29 | unsigned long int reserved; 30 | /** Size of the block. */ 31 | unsigned long int size; 32 | /** 33 | * Copy function, generated by the compiler to help copy the block if it 34 | * contains nontrivial copy operations. 35 | */ 36 | void (*copy_helper)(void *dst, void *src); 37 | /** 38 | * Dispose function, generated by the compiler to help copy the block if it 39 | * contains nontrivial destructors. 40 | */ 41 | void (*dispose_helper)(void *src); 42 | /** 43 | * Objective-C type encoding of the block. 44 | */ 45 | const char *encoding; 46 | }; 47 | 48 | /** 49 | * Checks whether the block is currently being deallocated. 50 | * 51 | * Used by ARC weak reference management. Only call this after the weak 52 | * reference lock is acquired. 53 | */ 54 | OBJC_PUBLIC BLOCKS_EXPORT bool _Block_isDeallocating(const void *aBlock); 55 | /** 56 | * Atomically increments the reference count of the block. 57 | * Returns true if the block was retained, and false if it is already 58 | * being deallocated. 59 | * 60 | * Used by ARC weak reference management. Only call this after the weak 61 | * reference lock is acquired. 62 | */ 63 | OBJC_PUBLIC BLOCKS_EXPORT bool _Block_tryRetain(const void *aBlock); 64 | 65 | // Helper structure 66 | struct Block_layout 67 | { 68 | /** 69 | * Class pointer. Always initialised to &_NSConcreteStackBlock for blocks 70 | * that are created on the stack or &_NSConcreteGlobalBlock for blocks that 71 | * are created in global storage. 72 | */ 73 | void *isa; 74 | /** 75 | * Flags. See the block_flags enumerated type for possible values. 76 | */ 77 | int flags; 78 | /** 79 | * Reserved - always initialised to 0 by the compiler. Used for the 80 | * reference count in this implementation. 81 | */ 82 | int reserved; 83 | /** 84 | * The function that implements the block. The first argument is this 85 | * structure, the subsequent arguments are the block's explicit parameters. 86 | * If the BLOCK_USE_SRET flag is set, there is an additional hidden 87 | * argument, which is a pointer to the space on the stack allocated to hold 88 | * the return value. 89 | */ 90 | void (*invoke)(void *, ...); 91 | /** 92 | * The block's descriptor. This is either Block_descriptor_basic or 93 | * Block_descriptor, depending on whether the 94 | * BLOCK_HAS_COPY_DISPOSE flag is set. 95 | */ 96 | struct Block_descriptor *descriptor; 97 | /** 98 | * Block variables are appended to this structure. 99 | */ 100 | }; 101 | 102 | 103 | 104 | #ifndef __OBJC_RUNTIME_INTERNAL__ 105 | /* 106 | * Deprecated Block_basic datastructure needed by libdispatch 107 | */ 108 | struct Block_basic { 109 | void *isa; 110 | int Block_flags; 111 | int Block_size; 112 | void (*Block_invoke)(void *); 113 | void (*Block_copy)(void *dst, void *src); 114 | void (*Block_dispose)(void *); 115 | }; 116 | #endif // __OBJC_RUNTIME_INTERNAL__ 117 | #endif //__LIBOBJC_BLOCKS_PRIVATE_H_INCLUDED__ 118 | 119 | -------------------------------------------------------------------------------- /objc/blocks_runtime.h: -------------------------------------------------------------------------------- 1 | #if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__) 2 | #pragma clang system_header 3 | #endif 4 | 5 | 6 | /* 7 | * Blocks Runtime 8 | */ 9 | #include "Availability.h" 10 | #include 11 | #ifdef __cplusplus 12 | #define BLOCKS_EXPORT extern "C" 13 | #else 14 | #define BLOCKS_EXPORT extern 15 | #endif 16 | 17 | OBJC_PUBLIC BLOCKS_EXPORT void *_Block_copy(const void *); 18 | OBJC_PUBLIC BLOCKS_EXPORT void _Block_release(const void *); 19 | OBJC_PUBLIC BLOCKS_EXPORT const char *block_getType_np(const void *b) OBJC_NONPORTABLE; 20 | 21 | OBJC_PUBLIC BLOCKS_EXPORT bool _Block_has_signature(void *); 22 | OBJC_PUBLIC BLOCKS_EXPORT const char * _Block_signature(void *); 23 | 24 | 25 | #define Block_copy(x) ((__typeof(x))_Block_copy((const void *)(x))) 26 | #define Block_release(x) _Block_release((const void *)(x)) 27 | -------------------------------------------------------------------------------- /objc/developer.h: -------------------------------------------------------------------------------- 1 | #if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__) 2 | #pragma clang system_header 3 | #endif 4 | 5 | enum objc_developer_mode_np 6 | { 7 | /** User mode - the default. */ 8 | objc_developer_mode_user, 9 | /** Developer mode - allows replacing classes. */ 10 | objc_developer_mode_developer 11 | }; 12 | /* 13 | * Sets the developer mode. When in user mode (the default), 14 | * loading two classes with the same name will cause the program to abort. In 15 | * developer mode, the new class will replace the old one. If the ivar layouts 16 | * are the same, the new class will be treated as a category. If they are 17 | * different, then it will replace the old one in the class table, meaning that 18 | * message sends to the class will go to the new version, but existing 19 | * instances will not acquire the new methods. 20 | * 21 | * The runtime currently only supports two modes, although more may be added in 22 | * the future. The behaviour of the existing modes will be maintained if this 23 | * is the case. 24 | */ 25 | void objc_setDeveloperMode_np(enum objc_developer_mode_np); 26 | -------------------------------------------------------------------------------- /objc/encoding.h: -------------------------------------------------------------------------------- 1 | #if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__) 2 | #pragma clang system_header 3 | #endif 4 | #include "objc-visibility.h" 5 | 6 | #ifndef __LIBOBJC_ENCODING_H_INCLUDED__ 7 | #define __LIBOBJC_ENCODING_H_INCLUDED__ 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | OBJC_PUBLIC 14 | const char *objc_skip_type_qualifiers (const char *type); 15 | 16 | OBJC_PUBLIC 17 | const char *objc_skip_typespec(const char *type); 18 | 19 | OBJC_PUBLIC 20 | const char *objc_skip_argspec(const char *type); 21 | 22 | 23 | OBJC_PUBLIC 24 | size_t objc_sizeof_type(const char *type); 25 | 26 | OBJC_PUBLIC 27 | size_t objc_alignof_type(const char *type); 28 | 29 | OBJC_PUBLIC 30 | size_t objc_aligned_size(const char *type); 31 | 32 | OBJC_PUBLIC 33 | size_t objc_promoted_size(const char *type); 34 | 35 | OBJC_PUBLIC 36 | void method_getReturnType(Method method, char *dst, size_t dst_len); 37 | 38 | OBJC_PUBLIC 39 | const char *method_getTypeEncoding(Method method); 40 | 41 | OBJC_PUBLIC 42 | SEL method_getTypedSelector_np(Method method) OBJC_NONPORTABLE; 43 | 44 | OBJC_PUBLIC 45 | void method_getArgumentType(Method method, 46 | unsigned int index, 47 | char *dst, 48 | size_t dst_len); 49 | 50 | OBJC_PUBLIC 51 | unsigned method_getNumberOfArguments(Method method); 52 | 53 | OBJC_PUBLIC 54 | unsigned method_get_number_of_arguments(struct objc_method *method); 55 | 56 | OBJC_PUBLIC 57 | char * method_copyArgumentType(Method method, unsigned int index); 58 | 59 | OBJC_PUBLIC 60 | char * method_copyReturnType(Method method); 61 | 62 | //////////////////////////////////////////////////////////////////////////////// 63 | // Deprecated functions - do not use functions below this line in new code. 64 | //////////////////////////////////////////////////////////////////////////////// 65 | OBJC_PUBLIC 66 | unsigned objc_get_type_qualifiers (const char *type); 67 | 68 | struct objc_struct_layout 69 | { 70 | const char *original_type; 71 | const char *type; 72 | const char *prev_type; 73 | unsigned int record_size; 74 | unsigned int record_align; 75 | }; 76 | 77 | // Note: The implementations of these functions is horrible. 78 | OBJC_PUBLIC 79 | void objc_layout_structure (const char *type, 80 | struct objc_struct_layout *layout); 81 | 82 | OBJC_PUBLIC 83 | BOOL objc_layout_structure_next_member(struct objc_struct_layout *layout); 84 | 85 | OBJC_PUBLIC 86 | void objc_layout_structure_get_info (struct objc_struct_layout *layout, 87 | unsigned int *offset, 88 | unsigned int *align, 89 | const char **type); 90 | 91 | #define _F_CONST 0x01 92 | #define _F_IN 0x01 93 | #define _F_OUT 0x02 94 | #define _F_INOUT 0x03 95 | #define _F_BYCOPY 0x04 96 | #define _F_BYREF 0x08 97 | #define _F_ONEWAY 0x10 98 | #define _F_GCINVISIBLE 0x20 99 | 100 | #ifdef __cplusplus 101 | } 102 | #endif 103 | 104 | #endif // __LIBOBJC_ENCODING_H_INCLUDED__ 105 | -------------------------------------------------------------------------------- /objc/objc-api.h: -------------------------------------------------------------------------------- 1 | #if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__) 2 | #pragma clang system_header 3 | #endif 4 | 5 | #include 6 | -------------------------------------------------------------------------------- /objc/objc-class.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | -------------------------------------------------------------------------------- /objc/objc-config.h.in: -------------------------------------------------------------------------------- 1 | #cmakedefine STRICT_APPLE_COMPATIBILITY @STRICT_APPLE_COMPATIBILITY@ 2 | -------------------------------------------------------------------------------- /objc/objc-exception.h: -------------------------------------------------------------------------------- 1 | #if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__) 2 | #pragma clang system_header 3 | #endif 4 | #include "objc-visibility.h" 5 | 6 | #ifndef __OBJC_EXCEPTION_INCLUDED__ 7 | #define __OBJC_EXCEPTION_INCLUDED__ 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | typedef void (*objc_uncaught_exception_handler)(id exception); 14 | 15 | /** 16 | * Throw a runtime exception. Inserted by the compiler in place of @throw. 17 | */ 18 | OBJC_PUBLIC 19 | void objc_exception_throw(id object); 20 | 21 | /** 22 | * Installs handler for uncaught Objective-C exceptions. If the unwind library 23 | * reaches the end of the stack without finding a handler then the handler is 24 | * called. Returns the previous handler. 25 | */ 26 | OBJC_PUBLIC 27 | objc_uncaught_exception_handler objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler handler); 28 | 29 | #ifdef __cplusplus 30 | } 31 | #endif 32 | 33 | #endif // __OBJC_EXCEPTION_INCLUDED__ 34 | -------------------------------------------------------------------------------- /objc/objc-runtime.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | -------------------------------------------------------------------------------- /objc/objc-visibility.h: -------------------------------------------------------------------------------- 1 | #if defined _WIN32 || defined __CYGWIN__ 2 | # ifdef __OBJC_RUNTIME_INTERNAL__ 3 | # define OBJC_PUBLIC __attribute__((dllexport)) 4 | # else 5 | # define OBJC_PUBLIC __attribute__((dllimport)) 6 | # endif 7 | #else 8 | # define OBJC_PUBLIC 9 | #endif 10 | -------------------------------------------------------------------------------- /objc/objc.h: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /objc/runtime-deprecated.h: -------------------------------------------------------------------------------- 1 | #if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__) 2 | #pragma clang system_header 3 | #endif 4 | 5 | #if !defined(__GNUSTEP_LIBOBJC_RUNTIME_DEPRECATED_INCLUDED__) && !defined(GNUSTEP_LIBOBJC_NO_LEGACY) 6 | # define __GNUSTEP_LIBOBJC_RUNTIME_DEPRECATED_INCLUDED__ 7 | 8 | /** 9 | * Legacy GNU runtime compatibility. 10 | * 11 | * All of the functions in this section are deprecated and should not be used 12 | * in new code. 13 | */ 14 | 15 | OBJC_PUBLIC 16 | __attribute__((deprecated)) 17 | void *objc_malloc(size_t size); 18 | 19 | OBJC_PUBLIC 20 | __attribute__((deprecated)) 21 | void *objc_atomic_malloc(size_t size); 22 | 23 | OBJC_PUBLIC 24 | __attribute__((deprecated)) 25 | void *objc_valloc(size_t size); 26 | 27 | OBJC_PUBLIC 28 | __attribute__((deprecated)) 29 | void *objc_realloc(void *mem, size_t size); 30 | 31 | OBJC_PUBLIC 32 | __attribute__((deprecated)) 33 | void * objc_calloc(size_t nelem, size_t size); 34 | 35 | OBJC_PUBLIC 36 | __attribute__((deprecated)) 37 | void objc_free(void *mem); 38 | 39 | OBJC_PUBLIC 40 | __attribute__((deprecated)) 41 | id objc_get_class(const char *name); 42 | 43 | OBJC_PUBLIC 44 | __attribute__((deprecated)) 45 | id objc_lookup_class(const char *name); 46 | 47 | OBJC_PUBLIC 48 | __attribute__((deprecated)) 49 | id objc_get_meta_class(const char *name); 50 | 51 | OBJC_PUBLIC 52 | #if !defined(__OBJC_RUNTIME_INTERNAL__) 53 | __attribute__((deprecated)) 54 | #endif 55 | Class objc_next_class(void **enum_state); 56 | 57 | OBJC_PUBLIC 58 | __attribute__((deprecated)) 59 | Class class_pose_as(Class impostor, Class super_class); 60 | 61 | OBJC_PUBLIC 62 | __attribute__((deprecated)) 63 | SEL sel_get_typed_uid (const char *name, const char *types); 64 | 65 | OBJC_PUBLIC 66 | __attribute__((deprecated)) 67 | SEL sel_get_any_typed_uid (const char *name); 68 | 69 | OBJC_PUBLIC 70 | __attribute__((deprecated)) 71 | SEL sel_get_any_uid (const char *name); 72 | 73 | OBJC_PUBLIC 74 | __attribute__((deprecated)) 75 | SEL sel_get_uid(const char *name); 76 | 77 | OBJC_PUBLIC 78 | __attribute__((deprecated)) 79 | const char *sel_get_name(SEL selector); 80 | 81 | OBJC_PUBLIC 82 | #if !defined(__OBJC_RUNTIME_INTERNAL__) 83 | __attribute__((deprecated)) 84 | #endif 85 | BOOL sel_is_mapped(SEL selector); 86 | 87 | OBJC_PUBLIC 88 | __attribute__((deprecated)) 89 | const char *sel_get_type(SEL selector); 90 | 91 | OBJC_PUBLIC 92 | __attribute__((deprecated)) 93 | SEL sel_register_name(const char *name); 94 | 95 | OBJC_PUBLIC 96 | __attribute__((deprecated)) 97 | SEL sel_register_typed_name(const char *name, const char *type); 98 | 99 | OBJC_PUBLIC 100 | __attribute__((deprecated)) 101 | BOOL sel_eq(SEL s1, SEL s2); 102 | 103 | #endif 104 | -------------------------------------------------------------------------------- /objc/slot.h: -------------------------------------------------------------------------------- 1 | #if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__) 2 | #pragma clang system_header 3 | #endif 4 | 5 | #ifndef __OBJC_SLOT_H_INCLUDED__ 6 | #define __OBJC_SLOT_H_INCLUDED__ 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | /** 13 | * The objc_slot structure is used to permit safe IMP caching. It is returned 14 | * by the new lookup APIs. When you call `objc_slot_lookup_version`, the final 15 | * parameter is used to return either the current value of 16 | * `objc_method_cache_version` or 0 if the slot is uncacheable. You can then 17 | * store this value along with a pointer to the `objc_slot2`. If the returned 18 | * value is equal to the current value of `objc_method_cache_version` then it 19 | * is safe to call the method from the `method` field of the slot directly. 20 | */ 21 | struct objc_slot2 22 | { 23 | IMP method; 24 | } OBJC_NONPORTABLE; 25 | 26 | /** 27 | * A counter that is incremented whenever one or more cached slots become 28 | * invalid, for example if a subclass loads a category containing methods that 29 | * were inherited from the superclass. 30 | * 31 | * Caching is disabled on targets without native 64-bit atomics support such 32 | * as PowerPC 32-bit. 33 | */ 34 | #if defined(__powerpc__) && !defined(__powerpc64__) 35 | #else 36 | OBJC_PUBLIC extern _Atomic(uint64_t) objc_method_cache_version; 37 | #endif 38 | 39 | /** 40 | * Legacy cache structure. This is no longer maintained in the runtime and is 41 | * now exported only in the compatibility interfaces. Slots of this form are 42 | * never cacheable. 43 | */ 44 | struct objc_slot 45 | { 46 | /** The class to which this slot is attached (used internally). */ 47 | Class owner; 48 | /** The class for which this slot was cached. Note that this can be 49 | * modified by different cache owners, in different threads. Doing so may 50 | * cause some cache misses, but if different methods are sending messages 51 | * to the same object and sharing a cached slot then it may also improve 52 | * cache hits. Profiling is probably required here. */ 53 | Class cachedFor; 54 | /** The (typed) selector for the method identified by this slot. */ 55 | const char *types; 56 | /** The current version. This changes if the method changes or if a 57 | * subclass overrides this method, potentially invalidating this cache. */ 58 | int version; 59 | /** The method pointer for this method. */ 60 | IMP method; 61 | /** Selector for this method. */ 62 | SEL selector; 63 | } OBJC_NONPORTABLE; 64 | #ifdef __cplusplus 65 | } 66 | #endif 67 | #endif // __OBJC_SLOT_H_INCLUDED__ 68 | -------------------------------------------------------------------------------- /objc/toydispatch.h: -------------------------------------------------------------------------------- 1 | /** 2 | * toydispatch implements a (tiny) subset of the libdispatch interfaces. It 3 | * can produce FIFO work queues, but not concurrent ones (although queues are 4 | * concurrent with respect to each other, as with libdispatch). Unlike 5 | * libdispatch, queues all run on the same system thread. This is less 6 | * efficient, so the real libdispatch should be used on platforms where it is 7 | * available. 8 | * 9 | * Toydispatch symbol names are prefixed with toy_ so programs can be linked to 10 | * both libdispatch and toydispatch. 11 | */ 12 | 13 | /* If the real libdispatch exists, use that instead of the toy one. */ 14 | #if !defined(__has_include) 15 | #define __has_include(x) 0 16 | #endif 17 | #if __has_include() && !defined(__TOY_DISPATCH__) 18 | # include 19 | #else 20 | 21 | /** 22 | * Function type for functions that can be added to dispatch queues. 23 | */ 24 | typedef void (*dispatch_function_t)(void *); 25 | 26 | typedef struct dispatch_queue * dispatch_queue_t; 27 | 28 | #define dispatch_queue_create toy_dispatch_queue_create 29 | /** 30 | * Create a new queue. Both parameters are ignored by toydispatch. 31 | */ 32 | dispatch_queue_t dispatch_queue_create(const char *label, void *attr); 33 | 34 | #define dispatch_async_f toy_dispatch_async_f 35 | /** 36 | * Add a function to the queue. 37 | */ 38 | void dispatch_async_f(dispatch_queue_t queue, 39 | void *context, 40 | dispatch_function_t work); 41 | 42 | #define dispatch_release toy_dispatch_release 43 | void dispatch_release(dispatch_queue_t queue); 44 | 45 | #define dispatch_retain toy_dispatch_retain 46 | void dispatch_retain(dispatch_queue_t queue); 47 | #endif 48 | -------------------------------------------------------------------------------- /objc_msgSend.S: -------------------------------------------------------------------------------- 1 | #include "common.S" 2 | #include "asmconstants.h" 3 | #if __x86_64 4 | #include "objc_msgSend.x86-64.S" 5 | #elif __i386 6 | #include "objc_msgSend.x86-32.S" 7 | #elif __arm__ 8 | #include "objc_msgSend.arm.S" 9 | #elif defined(__ARM_ARCH_ISA_A64) 10 | #include "objc_msgSend.aarch64.S" 11 | #elif defined(__riscv) && (__riscv_xlen == 64) && defined(__riscv_float_abi_double) 12 | #include "objc_msgSend.riscv64.S" 13 | #elif defined(__mips_n64) || defined(__mips_n32) 14 | #include "objc_msgSend.mips.S" 15 | #else 16 | #warning objc_msgSend() not implemented for your architecture 17 | #endif 18 | #ifdef __ELF__ 19 | .section .note.GNU-stack,"",%progbits 20 | #endif 21 | -------------------------------------------------------------------------------- /objc_msgSend.riscv64.S: -------------------------------------------------------------------------------- 1 | #define ARGUMENT_SPILL_SIZE (10*8 + 8*8) 2 | 3 | .macro MSGSEND receiver, sel 4 | .cfi_startproc 5 | beqz \receiver, 3f // Skip everything if receiver is nil 6 | 7 | andi t0, \receiver, SMALLOBJ_MASK 8 | bnez t0, 5f 9 | 10 | ld t0, 0(\receiver) // Load class into t0 11 | 0: 12 | ld t0, DTABLE_OFFSET(t0) // dtable -> t0 13 | ld t1, 0(\sel) // selector->index -> t1 14 | ld t2, SHIFT_OFFSET(t0) // dtable->shift -> t2 15 | 16 | li t3, 8 17 | beq t2, t3, 1f 18 | beqz t2, 2f 19 | 20 | srli t2, t1, 16-3 // Extract byte 3 of sel index and multiply by 2^3 21 | and t2, t2, 0x7F8 // Mask target byte 22 | // Example: ((0xCAFEBA >> 13) & 0x7f8) == (0xCA << 3) 23 | add t2, t0, t2 // t2 = dtable address + offset 24 | ld t0, DATA_OFFSET(t2) // Load, adding in the data offset 25 | 1: 26 | srli t2, t1, 8-3 // Extract byte 2 of sel index and multiply by 2^3 27 | and t2, t2, 0x7F8 // Mask target byte 28 | add t2, t0, t2 // t2 = dtable address + offset 29 | ld t0, DATA_OFFSET(t2) // Load, adding in the data offset 30 | 2: 31 | slli t2, t1, 3 // Multiply by 2^3 32 | and t2, t2, 0x7F8 // Mask target byte 33 | add t2, t0, t2 // t2 = dtable address + offset 34 | ld t0, DATA_OFFSET(t2) // Load, adding in the data offset 35 | // Slot pointer is now in t0 36 | 37 | beqz t0, 4f // If the slot is nil, go to the C path 38 | 39 | ld t0, SLOT_OFFSET(t0) // Load the method from the slot 40 | jalr zero, t0, 0 // Tail-call the method 41 | 42 | 3: 43 | li \receiver, 0 44 | li \sel, 0 45 | fmv.d.x fa0, zero 46 | fmv.d.x fa1, zero 47 | jalr zero, ra, 0 48 | 49 | 4: 50 | add sp, sp, -(ARGUMENT_SPILL_SIZE) 51 | 52 | // Spill function arguments 53 | sd a0, 0(sp) 54 | sd a1, 8(sp) 55 | sd a2, 16(sp) 56 | sd a3, 24(sp) 57 | sd a4, 32(sp) 58 | sd a5, 40(sp) 59 | sd a6, 48(sp) 60 | sd a7, 56(sp) 61 | 62 | // Spill FP arguments 63 | fsd fa0, 64(sp) 64 | fsd fa1, 72(sp) 65 | fsd fa2, 80(sp) 66 | fsd fa3, 88(sp) 67 | fsd fa4, 96(sp) 68 | fsd fa5, 104(sp) 69 | fsd fa6, 112(sp) 70 | fsd fa7, 120(sp) 71 | 72 | sd fp, 128(sp) 73 | sd ra, 136(sp) 74 | 75 | add fp, sp, 128 76 | add sp, sp, -16 77 | 78 | sd \receiver, 0(sp) // it is convenient if \receiver is spilled at sp 79 | 80 | .cfi_def_cfa fp, 16 81 | .cfi_offset fp, -16 82 | .cfi_offset ra, -8 83 | 84 | add a0, sp, zero // &self in first argument 85 | call CDECL(slowMsgLookup) 86 | 87 | add t0, a0, zero // IMP -> t0 88 | 89 | ld a0, 16(sp) 90 | ld a1, 24(sp) 91 | ld a2, 32(sp) 92 | ld a3, 40(sp) 93 | ld a4, 48(sp) 94 | ld a5, 56(sp) 95 | ld a6, 64(sp) 96 | ld a7, 72(sp) 97 | 98 | fld fa0, 80(sp) 99 | fld fa1, 88(sp) 100 | fld fa2, 96(sp) 101 | fld fa3, 104(sp) 102 | fld fa4, 112(sp) 103 | fld fa5, 120(sp) 104 | fld fa6, 128(sp) 105 | fld fa7, 136(sp) 106 | 107 | ld fp, 144(sp) 108 | ld ra, 152(sp) 109 | 110 | ld \receiver, 0(sp) 111 | 112 | add sp, sp, ARGUMENT_SPILL_SIZE 113 | add sp, sp, 16 114 | 115 | jalr zero, t0, 0 // Tail-call the method 116 | 117 | 5: 118 | // Load address of SmallObjectClasses 119 | auipc t1, %pcrel_hi(CDECL(SmallObjectClasses)) 120 | addi t1, t1, %pcrel_lo(5b) 121 | 122 | // Calculate array offset (INDEX * 2^3) 123 | slli t0, t0, 3 124 | add t0, t1, t0 125 | 126 | ld t0, 0(t0) 127 | 128 | j 0b 129 | .cfi_endproc 130 | .endm 131 | 132 | .globl CDECL(objc_msgSend_fpret) 133 | TYPE_DIRECTIVE(CDECL(objc_msgSend_fpret), %function) 134 | .globl CDECL(objc_msgSend) 135 | TYPE_DIRECTIVE(CDECL(objc_msgSend), %function) 136 | .globl CDECL(objc_msgSend_stret) 137 | CDECL(objc_msgSend): 138 | CDECL(objc_msgSend_fpret): 139 | MSGSEND a0, a1 140 | CDECL(objc_msgSend_stret): 141 | MSGSEND a1, a2 // Pointer to stack frame in a0 142 | -------------------------------------------------------------------------------- /objcxx_eh.h: -------------------------------------------------------------------------------- 1 | #ifdef __cplusplus 2 | extern "C" { 3 | #endif 4 | /** 5 | * Allocates a C++ exception. This function is part of the Itanium C++ ABI and 6 | * is provided externally. 7 | */ 8 | /* 9 | * Note: Recent versions of libsupc++ already provide a prototype for 10 | * __cxa__allocate_exception(). Since the libsupc++ version is defined with 11 | * _GLIBCXX_NOTHROW, clang gives a type mismatch error. 12 | */ 13 | #ifndef __cplusplus 14 | #undef CXA_ALLOCATE_EXCEPTION_SPECIFIER 15 | #define CXA_ALLOCATE_EXCEPTION_SPECIFIER 16 | #endif 17 | void *__cxa_allocate_exception(size_t thrown_size) CXA_ALLOCATE_EXCEPTION_SPECIFIER; 18 | 19 | /** 20 | * Initialises an exception object returned by __cxa_allocate_exception() for 21 | * storing an Objective-C object. The return value is the location of the 22 | * _Unwind_Exception structure within this structure, and should be passed to 23 | * the C++ personality function. 24 | */ 25 | struct _Unwind_Exception *objc_init_cxx_exception(id thrown_exception); 26 | /** 27 | * The GNU C++ exception personality function, provided by libsupc++ (GNU) or 28 | * libcxxrt (PathScale). 29 | */ 30 | __attribute__((weak)) DECLARE_PERSONALITY_FUNCTION(__gxx_personality_v0); 31 | /** 32 | * Frees an exception object allocated by __cxa_allocate_exception(). Part of 33 | * the Itanium C++ ABI. 34 | */ 35 | void __cxa_free_exception(void *thrown_exception); 36 | /** 37 | * Tests whether a C++ exception contains an Objective-C object, and returns if 38 | * if it does. The second argument is a pointer to a boolean value indicating 39 | * whether this is a valid object. 40 | */ 41 | void *objc_object_for_cxx_exception(void *thrown_exception, int *isValid); 42 | 43 | /** 44 | * Prints the type info associated with an exception. Used only when 45 | * debugging, not compiled in the normal build. 46 | */ 47 | void print_type_info(void *thrown_exception); 48 | 49 | /** 50 | * The exception class that we've detected that C++ runtime library uses. 51 | */ 52 | extern uint64_t cxx_exception_class; 53 | 54 | /** 55 | * The exception class that libsupc++ and libcxxrt use. 56 | */ 57 | const uint64_t gnu_cxx_exception_class = EXCEPTION_CLASS('G','N','U','C','C','+','+','\0'); 58 | 59 | /** 60 | * The exception class that libc++abi uses. 61 | */ 62 | const uint64_t llvm_cxx_exception_class = EXCEPTION_CLASS('C','L','N','G','C','+','+','\0'); 63 | 64 | #ifdef __cplusplus 65 | } 66 | #endif 67 | -------------------------------------------------------------------------------- /objcxx_eh_mingw.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "dwarf_eh.h" 6 | #include "objcxx_eh_private.h" 7 | #include "objcxx_eh.h" 8 | #include "objc/runtime.h" 9 | #include "objc/objc-arc.h" 10 | #include "objc/objc-exception.h" 11 | #include "objc/hooks.h" 12 | 13 | namespace __cxxabiv1 14 | { 15 | struct __cxa_refcounted_exception 16 | { 17 | int referenceCount; 18 | }; 19 | } 20 | 21 | using namespace __cxxabiv1; 22 | 23 | extern "C" __cxa_refcounted_exception* __cxa_init_primary_exception(void *obj, std::type_info *tinfo, void (*dest) (void *)); 24 | 25 | static void eh_cleanup(void *exception) 26 | { 27 | DEBUG_LOG("eh_cleanup: Releasing 0x%x\n", *(id*)exception); 28 | objc_release(*(id*)exception); 29 | } 30 | 31 | /** 32 | * Flag indicating that we've already inspected a C++ exception and found all 33 | * of the offsets. 34 | */ 35 | std::atomic done_setup; 36 | 37 | /** 38 | * The size of the `_Unwind_Exception` (including padding) in a 39 | * `__cxa_exception`. 40 | */ 41 | std::atomic exception_struct_size; 42 | 43 | extern "C" 44 | OBJC_PUBLIC 45 | void objc_exception_throw(id object) 46 | { 47 | // Don't bother with a mutex here. It doesn't matter if two threads set 48 | // these values at the same time. 49 | if (!done_setup) 50 | { 51 | DEBUG_LOG("objc_exception_throw: Doing initial setup\n"); 52 | MagicValueHolder *magicExc = (MagicValueHolder *)__cxa_allocate_exception(sizeof(MagicValueHolder)); 53 | MagicValueHolder x; 54 | *magicExc = x; 55 | 56 | __cxa_refcounted_exception *header = 57 | __cxa_init_primary_exception(magicExc, & __objc_id_type_info, NULL); 58 | exception_struct_size = find_forwards(header, MagicValueHolder::magic); 59 | __cxa_free_exception(magicExc); 60 | 61 | DEBUG_LOG("objc_exception_throw: exception_struct_size: 0x%x\n", unsigned(exception_struct_size)); 62 | 63 | done_setup = true; 64 | } 65 | 66 | id *exc = (id *)__cxa_allocate_exception(sizeof(id)); 67 | *exc = object; 68 | objc_retain(object); 69 | DEBUG_LOG("objc_exception_throw: Throwing 0x%x\n", *exc); 70 | 71 | __cxa_eh_globals *globals = __cxa_get_globals (); 72 | globals->uncaughtExceptions += 1; 73 | __cxa_refcounted_exception *header = 74 | __cxa_init_primary_exception(exc, & __objc_id_type_info, eh_cleanup); 75 | header->referenceCount = 1; 76 | 77 | _Unwind_Exception *unwindHeader = pointer_add<_Unwind_Exception>(header, exception_struct_size - sizeof(_Unwind_Exception)); 78 | _Unwind_Reason_Code err = _Unwind_RaiseException (unwindHeader); 79 | 80 | if (_URC_END_OF_STACK == err && 0 != _objc_unexpected_exception) 81 | { 82 | DEBUG_LOG("Invoking _objc_unexpected_exception\n"); 83 | _objc_unexpected_exception(object); 84 | } 85 | DEBUG_LOG("Throw returned %d\n",(int) err); 86 | abort(); 87 | } 88 | 89 | OBJC_PUBLIC extern objc_uncaught_exception_handler objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler handler) 90 | { 91 | return __atomic_exchange_n(&_objc_unexpected_exception, handler, __ATOMIC_SEQ_CST); 92 | } 93 | 94 | extern "C" void* __cxa_begin_catch(void *object); 95 | 96 | extern "C" 97 | OBJC_PUBLIC 98 | void* objc_begin_catch(void* object) 99 | { 100 | return __cxa_begin_catch(object); 101 | } 102 | 103 | extern "C" void __cxa_end_catch(); 104 | 105 | extern "C" 106 | OBJC_PUBLIC 107 | void objc_end_catch() 108 | { 109 | __cxa_end_catch(); 110 | } 111 | 112 | extern "C" void __cxa_rethrow(); 113 | 114 | extern "C" 115 | OBJC_PUBLIC 116 | void objc_exception_rethrow() 117 | { 118 | __cxa_rethrow(); 119 | } 120 | 121 | extern "C" EXCEPTION_DISPOSITION __gxx_personality_seh0(PEXCEPTION_RECORD ms_exc, 122 | void *this_frame, 123 | PCONTEXT ms_orig_context, 124 | PDISPATCHER_CONTEXT ms_disp); 125 | 126 | extern "C" 127 | OBJC_PUBLIC 128 | EXCEPTION_DISPOSITION __gnu_objc_personality_seh0(PEXCEPTION_RECORD ms_exc, 129 | void *this_frame, 130 | PCONTEXT ms_orig_context, 131 | PDISPATCHER_CONTEXT ms_disp) 132 | { 133 | return __gxx_personality_seh0(ms_exc, this_frame, ms_orig_context, ms_disp); 134 | } 135 | -------------------------------------------------------------------------------- /pool.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include "lock.h" 3 | 4 | #ifndef POOL_TYPE 5 | #error POOL_TYPE must be defined 6 | #endif 7 | #ifndef POOL_TYPE 8 | #error POOL_NAME must be defined 9 | #endif 10 | 11 | // Horrible multiple indirection to satisfy the weird precedence rules in cpp 12 | #define REALLY_PREFIX_SUFFIX(x,y) x ## y 13 | #define PREFIX_SUFFIX(x, y) REALLY_PREFIX_SUFFIX(x, y) 14 | #define NAME(x) PREFIX_SUFFIX(POOL_NAME, x) 15 | 16 | #define PAGE_SIZE 4096 17 | 18 | // Malloc one page at a time. 19 | #define POOL_SIZE ((PAGE_SIZE) / sizeof(POOL_TYPE)) 20 | static POOL_TYPE* NAME(_pool); 21 | static int NAME(_pool_next_index) = -1; 22 | 23 | #ifdef THREAD_SAFE_POOL 24 | static mutex_t NAME(_lock); 25 | #define LOCK_POOL() LOCK(&POOL_NAME##_lock) 26 | #define UNLOCK_POOL() LOCK(&POOL_NAME##_lock) 27 | #else 28 | #define LOCK_POOL() 29 | #define UNLOCK_POOL() 30 | #endif 31 | 32 | static int pool_size = 0; 33 | static int pool_allocs = 0; 34 | static inline POOL_TYPE*NAME(_pool_alloc)(void) 35 | { 36 | LOCK_POOL(); 37 | pool_allocs++; 38 | if (0 > NAME(_pool_next_index)) 39 | { 40 | NAME(_pool) = malloc(PAGE_SIZE); 41 | NAME(_pool_next_index) = POOL_SIZE - 1; 42 | pool_size += PAGE_SIZE; 43 | } 44 | POOL_TYPE* new = &NAME(_pool)[NAME(_pool_next_index)--]; 45 | UNLOCK_POOL(); 46 | return new; 47 | } 48 | #undef NAME 49 | #undef POOL_SIZE 50 | #undef PAGE_SIZE 51 | #undef POOL_NAME 52 | #undef POOL_TYPE 53 | #undef LOCK_POOL 54 | #undef UNLOCK_POOL 55 | #ifdef THREAD_SAFE_POOL 56 | #undef THREAD_SAFE_POOL 57 | #endif 58 | -------------------------------------------------------------------------------- /pool.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifdef _WIN32 3 | #include "safewindows.h" 4 | #if defined(WINAPI_FAMILY) && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP && _WIN32_WINNT >= 0x0A00 5 | // Prefer the *FromApp versions when we're being built in a Windows Store App context on 6 | // Windows >= 10. *FromApp require the application to be manifested for "codeGeneration". 7 | #define VirtualAlloc VirtualAllocFromApp 8 | #define VirtualProtect VirtualProtectFromApp 9 | #endif // App family partition 10 | 11 | inline void *allocate_pages(size_t size) 12 | { 13 | return VirtualAlloc(nullptr, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 14 | } 15 | 16 | #else 17 | #include 18 | inline void *allocate_pages(size_t size) 19 | { 20 | void *ret = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); 21 | return ret == MAP_FAILED ? nullptr : ret; 22 | 23 | } 24 | #endif 25 | 26 | template 27 | class PoolAllocate 28 | { 29 | static constexpr size_t PageSize = 4096; 30 | static constexpr size_t ChunkSize = sizeof(T) * PageSize; 31 | static inline size_t index = PageSize; 32 | static inline T *buffer = nullptr; 33 | public: 34 | static T *allocate() 35 | { 36 | if (index == PageSize) 37 | { 38 | index = 0; 39 | buffer = static_cast(allocate_pages(ChunkSize)); 40 | } 41 | return &buffer[index++]; 42 | } 43 | }; 44 | 45 | 46 | -------------------------------------------------------------------------------- /prepare_android_env.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export ANDROID_NDK_HOME=~/Library/Android/sdk/ndk/24.0.8215888 4 | export TOOLCHAIN=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/darwin-x86_64 5 | export CCPREFIX=$TOOLCHAIN/bin/aarch64-linux-android24 6 | export CC="$CCPREFIX-clang" 7 | export CXX="$CCPREFIX-clang++" 8 | export OBJC="$CCPREFIX-clang" 9 | export OBJCXX="$CCPREFIX-clang++" 10 | export AS="$CCPREFIX-clang" 11 | export LD="$TOOLCHAIN/bin/ld.lld" 12 | export AR="$TOOLCHAIN/bin/llvm-ar" 13 | export RANLIB="$TOOLCHAIN/bin/llvm-ranlib" 14 | export STRIP="$TOOLCHAIN/bin/llvm-strip" 15 | export NM="$TOOLCHAIN/bin/llvm-nm" 16 | export OBJDUMP="$TOOLCHAIN/bin/llvm-objdump" 17 | export LDFLAGS="-fuse-ld=lld" 18 | export LIBS="-lc++_shared" 19 | 20 | cmake -B build \ 21 | -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake \ 22 | -DANDROID_ABI=arm64-v8a \ 23 | -DANDROID_NDK=$ANDROID_NDK_HOME \ 24 | -DANDROID_STL=c++_shared \ 25 | -DCMAKE_FIND_USE_CMAKE_PATH=false \ 26 | -DCMAKE_C_COMPILER=$CC \ 27 | -DCMAKE_CXX_COMPILER=$CXX \ 28 | -DCMAKE_ASM_COMPILER=$AS \ 29 | -DCMAKE_BUILD_TYPE=Debug \ 30 | -DTESTS=ON \ 31 | -DANDROID_PLATFORM=android-24 \ 32 | -G Ninja 33 | -------------------------------------------------------------------------------- /safewindows.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIBOBJC_SAFEWINDOWS_H_INCLUDED__ 2 | #define __LIBOBJC_SAFEWINDOWS_H_INCLUDED__ 3 | 4 | #pragma push_macro("BOOL") 5 | 6 | #ifdef BOOL 7 | #undef BOOL 8 | #endif 9 | #define BOOL _WINBOOL 10 | 11 | #include 12 | 13 | // Windows.h defines interface -> struct 14 | #ifdef interface 15 | #undef interface 16 | #endif 17 | 18 | #pragma pop_macro("BOOL") 19 | 20 | #endif // __LIBOBJC_SAFEWINDOWS_H_INCLUDED__ 21 | -------------------------------------------------------------------------------- /selector.h: -------------------------------------------------------------------------------- 1 | #ifndef OBJC_SELECTOR_H_INCLUDED 2 | #define OBJC_SELECTOR_H_INCLUDED 3 | #include 4 | #include "objc/runtime.h" 5 | 6 | /** 7 | * Structure used to store selectors in the list. 8 | */ 9 | // begin: objc_selector 10 | struct objc_selector 11 | { 12 | union 13 | { 14 | /** 15 | * The name of this selector. Used for unregistered selectors. 16 | */ 17 | const char *name; 18 | /** 19 | * The index of this selector in the selector table. When a selector 20 | * is registered with the runtime, its name is replaced by an index 21 | * uniquely identifying this selector. The index is used for dispatch. 22 | */ 23 | uintptr_t index; 24 | }; 25 | /** 26 | * The Objective-C type encoding of the message identified by this selector. 27 | */ 28 | const char * types; 29 | }; 30 | // end: objc_selector 31 | 32 | 33 | /** 34 | * Returns the untyped variant of a selector. 35 | */ 36 | __attribute__((unused)) 37 | static uint32_t get_untyped_idx(SEL aSel) 38 | { 39 | SEL untyped = sel_registerTypedName_np(sel_getName(aSel), 0); 40 | return untyped->index; 41 | } 42 | 43 | __attribute__((unused)) 44 | static SEL sel_getUntyped(SEL aSel) 45 | { 46 | return sel_registerTypedName_np(sel_getName(aSel), 0); 47 | } 48 | 49 | #ifdef __cplusplus 50 | extern "C" 51 | { 52 | #endif 53 | /** 54 | * Registers the selector. This selector may be returned later, so it must not 55 | * be freed. 56 | */ 57 | SEL objc_register_selector(SEL aSel); 58 | 59 | #ifdef __cplusplus 60 | } 61 | #endif 62 | 63 | /** 64 | * SELECTOR() macro to work around the fact that GCC hard-codes the type of 65 | * selectors. This is functionally equivalent to @selector(), but it ensures 66 | * that the selector has the type that the runtime uses for selectors. 67 | */ 68 | #ifdef __clang__ 69 | #define SELECTOR(x) @selector(x) 70 | #else 71 | #define SELECTOR(x) (SEL)@selector(x) 72 | #endif 73 | 74 | #endif // OBJC_SELECTOR_H_INCLUDED 75 | -------------------------------------------------------------------------------- /spinlock.h: -------------------------------------------------------------------------------- 1 | #ifdef _WIN32 2 | #include "safewindows.h" 3 | static unsigned sleep(unsigned seconds) 4 | { 5 | Sleep(seconds*1000); 6 | return 0; 7 | } 8 | #else 9 | #include 10 | #endif 11 | 12 | /** 13 | * Number of spinlocks. This allocates one page on 32-bit platforms. 14 | */ 15 | #define spinlock_count (1<<10) 16 | static const int spinlock_mask = spinlock_count - 1; 17 | /** 18 | * Integers used as spinlocks for atomic property access. 19 | */ 20 | extern int spinlocks[spinlock_count]; 21 | /** 22 | * Get a spin lock from a pointer. We want to prevent lock contention between 23 | * properties in the same object - if someone is stupid enough to be using 24 | * atomic property access, they are probably stupid enough to do it for 25 | * multiple properties in the same object. We also want to try to avoid 26 | * contention between the same property in different objects, so we can't just 27 | * use the ivar offset. 28 | */ 29 | static inline volatile int *lock_for_pointer(const void *ptr) 30 | { 31 | intptr_t hash = (intptr_t)ptr; 32 | // Most properties will be pointers, so disregard the lowest few bits 33 | hash >>= sizeof(void*) == 4 ? 2 : 8; 34 | intptr_t low = hash & spinlock_mask; 35 | hash >>= 16; 36 | hash |= low; 37 | return spinlocks + (hash & spinlock_mask); 38 | } 39 | 40 | /** 41 | * Unlocks the spinlock. This is not an atomic operation. We are only ever 42 | * modifying the lowest bit of the spinlock word, so it doesn't matter if this 43 | * is two writes because there is no contention among the high bit. There is 44 | * no possibility of contention among calls to this, because it may only be 45 | * called by the thread owning the spin lock. 46 | */ 47 | inline static void unlock_spinlock(volatile int *spinlock) 48 | { 49 | __sync_synchronize(); 50 | *spinlock = 0; 51 | } 52 | /** 53 | * Attempts to lock a spinlock. This is heavily optimised for the uncontended 54 | * case, because property access should (generally) not be contended. In the 55 | * uncontended case, this is a single atomic compare and swap instruction and a 56 | * branch. Atomic CAS is relatively expensive (can be a pipeline flush, and 57 | * may require locking a cache line in a cache-coherent SMP system, but it's a 58 | * lot cheaper than a system call). 59 | * 60 | * If the lock is contended, then we just sleep and then try again after the 61 | * other threads have run. Note that there is no upper bound on the potential 62 | * running time of this function, which is one of the great many reasons that 63 | * using atomic accessors is a terrible idea, but in the common case it should 64 | * be very fast. 65 | */ 66 | inline static void lock_spinlock(volatile int *spinlock) 67 | { 68 | int count = 0; 69 | // Set the spin lock value to 1 if it is 0. 70 | while(!__sync_bool_compare_and_swap(spinlock, 0, 1)) 71 | { 72 | count++; 73 | if (0 == count % 10) 74 | { 75 | // If it is already 1, let another thread play with the CPU for a 76 | // bit then try again. 77 | sleep(0); 78 | } 79 | } 80 | } 81 | 82 | -------------------------------------------------------------------------------- /statics_loader.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "objc/runtime.h" 4 | #include "module.h" 5 | #include "constant_string.h" 6 | #include "visibility.h" 7 | 8 | #define BUFFER_TYPE struct objc_static_instance_list * 9 | #include "buffer.h" 10 | 11 | static BOOL try_init_statics(struct objc_static_instance_list *statics) 12 | { 13 | const char *class_name = statics->class_name; 14 | 15 | // This is a horrible hack. 16 | // 17 | // Very bad things happen when you have more than one constant string class 18 | // used in a program. Unfortunately, GCC defaults to using 19 | // NXConstantString, and if you forget to specify 20 | // -fconstant-string-class=NSConstantString for some compilation units then 21 | // you will end up with some NSConstantString instances and some 22 | // NXConstantString instances. This is a mess. We hack around this by 23 | // silently assuming that the user meant NSConstantString when they said 24 | // NXConstantString if NSConstantString is set as the constant string class 25 | // in string_class.h or by an external -D flag. 26 | if (strcmp(class_name, "NXConstantString") == 0) 27 | { 28 | class_name = CONSTANT_STRING_CLASS; 29 | } 30 | 31 | Class class = (Class)objc_getClass(class_name); 32 | 33 | if (Nil == class) 34 | { 35 | return NO; 36 | } 37 | for (id *instance=statics->instances ; nil!=*instance ; instance++) 38 | { 39 | (*instance)->isa = class; 40 | } 41 | return YES; 42 | } 43 | PRIVATE void objc_init_statics(struct objc_static_instance_list *statics) 44 | { 45 | if (!try_init_statics(statics)) 46 | { 47 | set_buffered_object_at_index(statics, buffered_objects++); 48 | } 49 | } 50 | 51 | PRIVATE void objc_init_buffered_statics(void) 52 | { 53 | BOOL shouldReshuffle = NO; 54 | 55 | for (unsigned i=0 ; i 2 | #include 3 | 4 | /** 5 | * Efficient string hash function. 6 | */ 7 | __attribute__((unused)) 8 | static uint32_t string_hash(const char *str) 9 | { 10 | uint32_t hash = 0; 11 | int32_t c; 12 | while ((c = *str++)) 13 | { 14 | hash = c + (hash << 6) + (hash << 16) - hash; 15 | } 16 | return hash; 17 | } 18 | 19 | /** 20 | * Test two strings for equality. 21 | */ 22 | __attribute__((unused)) 23 | static int string_compare(const char *str1, const char *str2) 24 | { 25 | if (str1 == str2) 26 | { 27 | return 1; 28 | } 29 | if (str1 == NULL || str2 == NULL) 30 | { 31 | return 0; 32 | } 33 | return strcmp(str1, str2) == 0; 34 | } 35 | -------------------------------------------------------------------------------- /type_encoding_cases.h: -------------------------------------------------------------------------------- 1 | /** 2 | * type_encoding_cases.h - expects the APPLY_TYPE macro to be defined. This 3 | * macro is invoked once for every type and its Objective-C name. Use this 4 | * file when implementing things like the -unsignedIntValue family of methods. 5 | * For this case, the macro will be invoked with unsigned int as the type and 6 | * unsignedInt as the name. 7 | */ 8 | #ifndef APPLY_TYPE 9 | #error Define APPLY_TYPE(type, name, capitalizedName, encodingChar) before including this file 10 | #endif 11 | APPLY_TYPE(long double, long double, LongDouble, 'D') 12 | APPLY_TYPE(double, double, Double, 'd') 13 | APPLY_TYPE(float, float, Float, 'f') 14 | APPLY_TYPE(signed char, char, Char, 'c') 15 | APPLY_TYPE(int, int, Int, 'i') 16 | APPLY_TYPE(short, short, Short, 's') 17 | APPLY_TYPE(long, long, Long, 'l') 18 | APPLY_TYPE(long long, longLong, LongLong, 'q') 19 | //APPLY_TYPE(__int128, int128, Int128, 't') 20 | APPLY_TYPE(unsigned char, unsignedChar, UnsignedChar, 'C') 21 | APPLY_TYPE(unsigned short, unsignedShort, UnsignedShort, 'S') 22 | APPLY_TYPE(unsigned int, unsignedInt, UnsignedInt, 'I') 23 | APPLY_TYPE(unsigned long, unsignedLong, UnsignedLong, 'L') 24 | APPLY_TYPE(unsigned long long, unsignedLongLong, UnsignedLongLong, 'Q') 25 | //APPLY_TYPE(unsigned __int128, unsignedInt128, UnsignedInt128, 'T') 26 | #ifdef NON_INTEGER_TYPES 27 | #undef NON_INTEGER_TYPES 28 | APPLY_TYPE(_Bool, bool, Bool, 'B') 29 | #ifndef SKIP_ID 30 | APPLY_TYPE(id, object, Object, '@') 31 | #endif 32 | APPLY_TYPE(Class, class, Class, '#') 33 | APPLY_TYPE(SEL, selector, Selector, ':') 34 | APPLY_TYPE(char*, cString, CString, '*') 35 | #endif 36 | #undef APPLY_TYPE 37 | -------------------------------------------------------------------------------- /unwind.h: -------------------------------------------------------------------------------- 1 | #ifdef __arm__ 2 | #include "unwind-arm.h" 3 | #else 4 | #include "unwind-itanium.h" 5 | #endif 6 | -------------------------------------------------------------------------------- /visibility.h: -------------------------------------------------------------------------------- 1 | #include "objc/objc-visibility.h" 2 | 3 | #if defined _WIN32 || defined __CYGWIN__ 4 | # define PRIVATE 5 | #else 6 | # define PRIVATE __attribute__ ((visibility("hidden"))) 7 | #endif 8 | #ifdef NO_LEGACY 9 | # define LEGACY PRIVATE 10 | #else 11 | # define LEGACY OBJC_PUBLIC 12 | #endif 13 | 14 | #if defined(DEBUG) || (!defined(__clang__)) 15 | # include 16 | # define UNREACHABLE(x) assert(0 && x) 17 | # define ASSERT(x) assert(x) 18 | #else 19 | # define UNREACHABLE(x) __builtin_unreachable() 20 | # define ASSERT(x) do { if (!(x)) __builtin_unreachable(); } while(0) 21 | #endif 22 | 23 | #define LIKELY(x) __builtin_expect(x, 1) 24 | #define UNLIKELY(x) __builtin_expect(x, 0) 25 | --------------------------------------------------------------------------------