From 934cd13a7a346dc0f3d8466fd180a127354a0ee5 Mon Sep 17 00:00:00 2001 From: David Chisnall Date: Fri, 20 Jul 2018 17:13:30 +0100 Subject: [PATCH] Initial pass at Windows support. All tests now pass with the new ABI on x86-64, with the new ABI. Some of the code is ugly and other platforms are probably broken. --- CMakeLists.txt | 127 ++++++++++++++++++++++------------- NSBlocks.m | 19 +++--- Test/CMakeLists.txt | 31 +++++++-- Test/ManyManySelectors.m | 2 - Test/NestedExceptions.m | 1 + Test/PropertyAttributeTest.m | 2 +- Test/RuntimeTest.m | 11 ++- Test/objc_msgSend.m | 9 +-- alias.h | 2 +- alias_table.c | 4 +- arc.m | 58 ++++++++-------- asmconstants.h | 7 ++ associate.m | 2 + block_to_imp.c | 14 +++- blocks_runtime.m | 10 +-- caps.c | 2 +- dtable.h | 2 + eh_win32_msvc.cc | 91 ++++++++++++++++++------- encoding2.c | 4 ++ hash_table.h | 1 - loader.c | 7 +- objc/Availability.h | 1 + objc/blocks_runtime.h | 6 +- objc/capabilities.h | 1 + objc/hooks.h | 13 ++-- objc/message.h | 4 ++ objc/objc-arc.h | 51 +++++++------- objc/runtime.h | 119 ++++++++++++++++++++++++++++++-- objc_msgSend.S | 5 ++ objc_msgSend.x86-64.S | 83 +++++++++++++++++------ properties.m | 25 ++++++- unistd.h | 4 +- visibility.h | 4 +- 33 files changed, 522 insertions(+), 200 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a8371d..6393de9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,6 @@ cmake_minimum_required(VERSION 3.1) -project(libobjc) -enable_language(ASM) +project(libobjc C ASM CXX) INCLUDE (CheckCXXSourceCompiles) @@ -10,13 +9,15 @@ macro(install_symlink filepath sympath) install(CODE "message(\"-- Symlinking: ${sympath} -> ${filepath}\")") endmacro(install_symlink) -set(CMAKE_C_FLAGS_DEBUG "-g -O0 -fno-inline ${CMAKE_C_FLAGS_DEBUG}") +set(CMAKE_C_FLAGS_DEBUG "/Z7 -O0 -Xclang -fno-inline ${CMAKE_C_FLAGS_DEBUG}") +set(CMAKE_SHARED_LINKER_FLAGS "/DEBUG /INCREMENTAL:NO ${CMAKE_SHARED_LINKER_FLAGS}") set(CMAKE_C_FLAGS_RELEASE "-O3 ${CMAKE_C_FLAGS_RELEASE}") -set(CMAKE_C_FLAGS "-std=gnu99 ${CMAKE_C_FLAGS}") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") set(libobjc_VERSION 4.6) -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fexceptions") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /EHas -Xclang -fexceptions -Xclang -fobjc-exceptions") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHas") # Build configuration add_definitions( -DGNUSTEP -D__OBJC_RUNTIME_INTERNAL__=1) @@ -37,7 +38,6 @@ set(libobjc_C_SRCS category_loader.c class_table.c dtable.c - eh_personality.c encoding2.c hooks.c ivar.c @@ -68,10 +68,16 @@ set(libobjc_HDRS objc/objc.h objc/runtime-deprecated.h objc/runtime.h - objc/slot.h -) + objc/slot.h) + +# Windows does not use DWARF EH +if (WIN32) + list(APPEND libobjc_CXX_SRCS eh_win32_msvc.cc) +else () + list(APPEND libobjc_C_SRCS eh_personality.c) + set(libobjcxx_CXX_SRCS objcxx_eh.cc) +endif (WIN32) -set(libobjcxx_CXX_SRCS objcxx_eh.cc) # For release builds, we disable spamming the terminal with warnings about # selector type mismatches @@ -154,10 +160,26 @@ endif () set(INSTALL_TARGETS objc) +# On Windows, CMake adds /TC to the clang-cl flags and doesn't provide a way to +# tell it not to. We fix this by telling clang do disregard that option, +# unconditionally (which means that it still defaults to C for .c files). +set(ENV{CCC_OVERRIDE_OPTIONS} "x/TC x/Gm-") + +set_source_files_properties( + ${libobjc_ASM_SRCS} + LANGUAGE C + COMPILE_FLAGS "${CMAKE_OBJC_FLAGS} -Xclang -x -Xclang assembler-with-cpp" +) + +set_source_files_properties( + ${libobjc_CXX_SRCS} + LANGUAGE CXX + COMPILE_FLAGS "${CMAKE_CXX_FLAGS}" +) + set_source_files_properties( ${libobjc_OBJC_SRCS} - PROPERTIES LANGUAGE C - COMPILE_FLAGS "${CMAKE_OBJC_FLAGS}" + COMPILE_FLAGS "${CMAKE_OBJC_FLAGS} -Xclang -x -Xclang objective-c" ) # @@ -186,40 +208,55 @@ set(ENABLE_OBJCXX true CACHE BOOL set(CXXRT_IS_STDLIB false) -add_library(objc SHARED ${libobjc_C_SRCS} ${libobjc_ASM_SRCS} ${libobjc_OBJC_SRCS}) +add_custom_command(OUTPUT block_trampolines.obj + COMMAND ${CMAKE_C_COMPILER} -c "${CMAKE_SOURCE_DIR}/block_trampolines.S" -o "${CMAKE_BINARY_DIR}/block_trampolines.obj" + MAIN_DEPENDENCY block_trampolines.S +) +add_custom_command(OUTPUT objc_msgSend.obj + COMMAND ${CMAKE_C_COMPILER} -c "${CMAKE_SOURCE_DIR}/objc_msgSend.S" -o "${CMAKE_BINARY_DIR}/objc_msgSend.obj" + MAIN_DEPENDENCY objc_msgSend.S + DEPENDS objc_msgSend.aarch64.S objc_msgSend.arm.S objc_msgSend.mips.S objc_msgSend.x86-32.S objc_msgSend.x86-64.S +) + + +add_library(objc SHARED ${libobjc_C_SRCS} ${libobjc_ASM_SRCS} ${libobjc_OBJC_SRCS} block_trampolines.obj objc_msgSend.obj) if (ENABLE_OBJCXX) - message(STATUS "Testing C++ interop") - # Try to find libcxxrt.so. We can link to this to provide the C++ ABI - # layer, if it exists. - test_cxx(cxxrt false) - # If it doesn't, then look for GNU libsupc++.so instead (either works, - # they're ABI compatible). - if (NOT CXX_RUNTIME) - test_cxx(supc++ false) - endif (NOT CXX_RUNTIME) - if (NOT CXX_RUNTIME) - test_cxx(c++abi false) - endif (NOT CXX_RUNTIME) - - # If we have a C++ ABI library, then we can produce a single libobjc that - # works for Objective-C and Objective-C++. If not, then we need to provide - # a separate libobjcxx. - if (CXX_RUNTIME) - message(STATUS "Using ${CXX_RUNTIME} as the C++ runtime library") - else() - message(STATUS "Testing C++ standard library") - try_compile(USERUNTIME - "${CMAKE_BINARY_DIR}/CMake" - "${CMAKE_SOURCE_DIR}/CMake" - test_cxx_runtime) - if (${USERUNTIME}) - message(STATUS "libobjc will depend on C++ standard library") - set(CXXRT_IS_STDLIB true) + if (WIN32) + message(STATUS "Using MSVC-compatible exception model") + else () + message(STATUS "Testing C++ interop") + # Try to find libcxxrt.so. We can link to this to provide the C++ ABI + # layer, if it exists. + test_cxx(cxxrt false) + # If it doesn't, then look for GNU libsupc++.so instead (either works, + # they're ABI compatible). + if (NOT CXX_RUNTIME) + test_cxx(supc++ false) + endif (NOT CXX_RUNTIME) + if (NOT CXX_RUNTIME) + test_cxx(c++abi false) + endif (NOT CXX_RUNTIME) + + # If we have a C++ ABI library, then we can produce a single libobjc that + # works for Objective-C and Objective-C++. If not, then we need to provide + # a separate libobjcxx. + if (CXX_RUNTIME) + message(STATUS "Using ${CXX_RUNTIME} as the C++ runtime library") else() - message(STATUS "No useable C++ runtime found") - set(ENABLE_OBJCXX false) - endif() + message(STATUS "Testing C++ standard library") + try_compile(USERUNTIME + "${CMAKE_BINARY_DIR}/CMake" + "${CMAKE_SOURCE_DIR}/CMake" + test_cxx_runtime) + if (${USERUNTIME}) + message(STATUS "libobjc will depend on C++ standard library") + set(CXXRT_IS_STDLIB true) + else() + message(STATUS "No useable C++ runtime found") + set(ENABLE_OBJCXX false) + endif() + endif () endif () endif (ENABLE_OBJCXX) @@ -231,8 +268,8 @@ if (ENABLE_OBJCXX) set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "") target_link_libraries(objc ${CXX_RUNTIME}) endif() - set(libobjc_CXX_SRCS ${libobjcxx_CXX_SRCS}) - target_sources(objc PRIVATE ${libobjcxx_CXX_SRCS}) + list(APPEND libobjc_CXX_SRCS ${libobjcxx_CXX_SRCS}) + target_sources(objc PRIVATE ${libobjc_CXX_SRCS}) endif() @@ -264,8 +301,6 @@ if (BUILD_STATIC_LIBOBJC) list(APPEND INSTALL_TARGETS objc-static) endif () - - # Explicitly link libgc if we are compiling with gc support. if (LIBGC) target_link_libraries(objc ${LIBGC}) diff --git a/NSBlocks.m b/NSBlocks.m index 6bbd73c..c72b3d3 100644 --- a/NSBlocks.m +++ b/NSBlocks.m @@ -1,14 +1,14 @@ -#import "objc/runtime.h" -#import "class.h" -#import "loader.h" -#import "lock.h" -#import "objc/blocks_runtime.h" -#import "dtable.h" +#include "objc/runtime.h" +#include "class.h" +#include "loader.h" +#include "lock.h" +#include "objc/blocks_runtime.h" +#include "dtable.h" #include -struct objc_class _NSConcreteGlobalBlock; -struct objc_class _NSConcreteStackBlock; -struct objc_class _NSConcreteMallocBlock; +PUBLIC struct objc_class _NSConcreteGlobalBlock; +PUBLIC struct objc_class _NSConcreteStackBlock; +PUBLIC struct objc_class _NSConcreteMallocBlock; static struct objc_class _NSConcreteGlobalBlockMeta; static struct objc_class _NSConcreteStackBlockMeta; @@ -40,6 +40,7 @@ static void createNSBlockSubclass(Class superclass, Class newClass, #define NEW_CLASS(super, sub) \ createNSBlockSubclass(super, &sub, &sub ## Meta, #sub) +PUBLIC BOOL objc_create_block_classes_as_subclasses_of(Class super) { if (_NSBlock.super_class != NULL) { return NO; } diff --git a/Test/CMakeLists.txt b/Test/CMakeLists.txt index 79a71af..bd264ae 100644 --- a/Test/CMakeLists.txt +++ b/Test/CMakeLists.txt @@ -3,6 +3,16 @@ # the installed version +# On Windows, CMake adds /TC to the clang-cl flags and doesn't provide a way to +# tell it not to. We fix this by telling clang do disregard that option, +# unconditionally (which means that it still defaults to C for .c files). +set(ENV{CCC_OVERRIDE_OPTIONS} "x/TC x/TP") +set(INCREMENTAL " ") +if (MSVC) + set(CMAKE_EXE_LINKER_FLAGS "/DEBUG /INCREMENTAL:NO ${CMAKE_EXE_LINKER_FLAGS}") + set(INCREMENTAL "/INCREMENTAL:NO") +endif () + # List of single-file tests. set(TESTS alias.m @@ -14,10 +24,8 @@ set(TESTS BlockImpTest.m BlockTest_arc.m ConstantString.m - BoxedForeignException.m Category.m ExceptionTest.m - ForeignException.m Forward.m ManyManySelectors.m NestedExceptions.m @@ -43,24 +51,33 @@ set(TESTS setSuperclass.m ) +if (WIN32) +else () + list(APPEND TESTS + BoxedForeignException.m + ForeignException.m + ) +endif () + # List of single-file tests that won't work with the legacy ABI and so # shouldn't be run in legacy mode. set(NEW_TESTS category_properties.m ) +remove_definitions(-D__OBJC_RUNTIME_INTERNAL__=1) add_library(test_runtime_legacy OBJECT Test.m) set_target_properties(test_runtime_legacy PROPERTIES INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}" - COMPILE_FLAGS "-fblocks -fobjc-runtime=gnustep-1.7" + COMPILE_FLAGS "-Xclang -fblocks -fobjc-runtime=gnustep-1.7" LINKER_LANGUAGE C ) add_library(test_runtime OBJECT Test.m) set_target_properties(test_runtime PROPERTIES INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}" - COMPILE_FLAGS "-fblocks -fobjc-runtime=gnustep-2.0" + COMPILE_FLAGS "-Xclang -fblocks -fobjc-runtime=gnustep-2.0" LINKER_LANGUAGE C ) @@ -71,14 +88,14 @@ function(addtest_flags TEST_NAME FLAGS TEST_SOURCE) if (${TEST_NAME} MATCHES ".*_arc") # Only compile the main file with ARC set_source_files_properties(${TEST_SOURCE} - COMPILE_FLAGS "-fobjc-arc") + COMPILE_FLAGS "-Xclang -fobjc-arc") endif() add_executable(${TEST_NAME} ${TEST_SOURCE}) add_test(${TEST_NAME} ${TEST_NAME}) set(ARC "") set_target_properties(${TEST_NAME} PROPERTIES INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}" - COMPILE_FLAGS "-fblocks ${FLAGS}" + COMPILE_FLAGS "-Xclang -fblocks ${FLAGS}" LINKER_LANGUAGE C ) set_property(TEST ${TEST_NAME} PROPERTY @@ -114,5 +131,5 @@ endforeach() addtest_variants("CXXExceptions" "CXXException.m;CXXException.cc" true) addtest_variants("ForwardDeclareProtocolAccess" "ForwardDeclareProtocolAccess.m;ForwardDeclareProtocol.m" true) if (ENABLE_OBJCXX) -addtest_variants(ObjCXXEHInterop "ObjCXXEHInterop.mm;ObjCXXEHInterop.m" true) + addtest_variants(ObjCXXEHInterop "ObjCXXEHInterop.mm;ObjCXXEHInterop.m" true) endif() diff --git a/Test/ManyManySelectors.m b/Test/ManyManySelectors.m index 2e6f7d0..2c65212 100644 --- a/Test/ManyManySelectors.m +++ b/Test/ManyManySelectors.m @@ -4,8 +4,6 @@ #include #include -#include -#include static BOOL methodCalled = NO; diff --git a/Test/NestedExceptions.m b/Test/NestedExceptions.m index d312749..1399c68 100644 --- a/Test/NestedExceptions.m +++ b/Test/NestedExceptions.m @@ -26,6 +26,7 @@ int main(void) assert(x == e1); @try { a = e2; + @throw a; } @catch (id y) { diff --git a/Test/PropertyAttributeTest.m b/Test/PropertyAttributeTest.m index 990cf4d..de52d79 100644 --- a/Test/PropertyAttributeTest.m +++ b/Test/PropertyAttributeTest.m @@ -39,7 +39,7 @@ int main() assert(strcmp(property_getAttributes(property), "Ti,VvarName") == 0); free(properties); - objc_property_t *clsproperties = class_copyPropertyList(object_getClass([helloclass class]), &outCount); + properties = class_copyPropertyList(object_getClass([helloclass class]), &outCount); assert(outCount == 1); property = properties[0]; assert(strcmp(property_getName(property), "clsProp") == 0); diff --git a/Test/RuntimeTest.m b/Test/RuntimeTest.m index f2b6364..47560fa 100644 --- a/Test/RuntimeTest.m +++ b/Test/RuntimeTest.m @@ -1,7 +1,11 @@ #include "Test.h" #include #include -#include +#ifdef _WIN32 +# define sleep Sleep +#else +# include +#endif static int exitStatus = 0; @@ -125,10 +129,11 @@ id exceptionObj = @"Exception"; @catch (id e) { test(e == exceptionObj); + return YES; } - @finally + @catch(...) { - return YES; + return NO; } return NO; } diff --git a/Test/objc_msgSend.m b/Test/objc_msgSend.m index 2e86551..a47fc87 100644 --- a/Test/objc_msgSend.m +++ b/Test/objc_msgSend.m @@ -10,7 +10,6 @@ //#define assert(x) if (!(x)) { printf("Failed %d\n", __LINE__); } -id objc_msgSend(id, SEL, ...); typedef struct { int a,b,c,d,e; } s; @interface Fake @@ -81,13 +80,14 @@ __attribute__((objc_root_class)) + (void)printf: (const char*)str, ... { va_list ap; - char *s; + char s[100]; va_start(ap, str); - vasprintf(&s, str, ap); + vsnprintf(&s, 100, str, ap); va_end(ap); - //fprintf(stderr, "String: '%s'\n", s); + fprintf(stderr, "String: '%s'\n", s); + vfprintf(stderr, s, ap); assert(strcmp(s, "Format string 42 42.000000\n") ==0); } + (void)initialize @@ -174,6 +174,7 @@ struct objc_slot *forward_slot(id o, SEL s) } + int main(void) { __objc_msg_forward2 = forward; diff --git a/alias.h b/alias.h index edf5ef3..4a918fa 100644 --- a/alias.h +++ b/alias.h @@ -24,4 +24,4 @@ */ #include "objc/runtime.h" -Class alias_getClass(const char *alias_name); +PUBLIC Class alias_getClass(const char *alias_name); diff --git a/alias_table.c b/alias_table.c index 6bf2bd6..b1e661c 100644 --- a/alias_table.c +++ b/alias_table.c @@ -77,7 +77,7 @@ static Alias alias_table_get_safe(const char *alias_name) } -Class alias_getClass(const char *alias_name) +PUBLIC Class alias_getClass(const char *alias_name) { if (NULL == alias_name) { @@ -99,7 +99,7 @@ PRIVATE void alias_table_insert(Alias alias) alias_table_internal_insert(alias_table, alias); } -BOOL class_registerAlias_np(Class class, const char *alias) +PUBLIC BOOL class_registerAlias_np(Class class, const char *alias) { if ((NULL == alias) || (NULL == class)) { diff --git a/arc.m b/arc.m index 82c73be..8ebd24f 100644 --- a/arc.m +++ b/arc.m @@ -212,14 +212,14 @@ static const long weak_mask = ((size_t)1)<<((sizeof(size_t)*8)-1); */ static const long refcount_mask = ~weak_mask; -size_t object_getRetainCount_np(id obj) +PUBLIC size_t object_getRetainCount_np(id obj) { uintptr_t *refCount = ((uintptr_t*)obj) - 1; uintptr_t refCountVal = __sync_fetch_and_add(refCount, 0); return (((size_t)refCountVal) & refcount_mask) + 1; } -id objc_retain_fast_np(id obj) +PUBLIC id objc_retain_fast_np(id obj) { uintptr_t *refCount = ((uintptr_t*)obj) - 1; uintptr_t refCountVal = __sync_fetch_and_add(refCount, 0); @@ -292,7 +292,7 @@ static inline id retain(id obj) return [obj retain]; } -BOOL objc_release_fast_no_destroy_np(id obj) +PUBLIC BOOL objc_release_fast_no_destroy_np(id obj) { uintptr_t *refCount = ((uintptr_t*)obj) - 1; uintptr_t refCountVal = __sync_fetch_and_add(refCount, 0); @@ -330,7 +330,7 @@ BOOL objc_release_fast_no_destroy_np(id obj) return NO; } -void objc_release_fast_np(id obj) +PUBLIC void objc_release_fast_np(id obj) { if (objc_release_fast_no_destroy_np(obj)) { @@ -420,7 +420,7 @@ static inline id autorelease(id obj) return [obj autorelease]; } -unsigned long objc_arc_autorelease_count_np(void) +PUBLIC unsigned long objc_arc_autorelease_count_np(void) { struct arc_tls* tls = getARCThreadData(); unsigned long count = 0; @@ -434,7 +434,7 @@ unsigned long objc_arc_autorelease_count_np(void) } return count; } -unsigned long objc_arc_autorelease_count_for_object_np(id obj) +PUBLIC unsigned long objc_arc_autorelease_count_for_object_np(id obj) { struct arc_tls* tls = getARCThreadData(); unsigned long count = 0; @@ -488,7 +488,7 @@ void *objc_autoreleasePoolPush(void) if (0 == NewAutoreleasePool) { return NULL; } return NewAutoreleasePool(AutoreleasePool, SELECTOR(new)); } -void objc_autoreleasePoolPop(void *pool) +PUBLIC void objc_autoreleasePoolPop(void *pool) { if (useARCAutoreleasePool) { @@ -511,7 +511,7 @@ void objc_autoreleasePoolPop(void *pool) } } -id objc_autorelease(id obj) +PUBLIC id objc_autorelease(id obj) { if (nil != obj) { @@ -520,7 +520,7 @@ id objc_autorelease(id obj) return obj; } -id objc_autoreleaseReturnValue(id obj) +PUBLIC id objc_autoreleaseReturnValue(id obj) { if (!useARCAutoreleasePool) { @@ -535,7 +535,7 @@ id objc_autoreleaseReturnValue(id obj) return objc_autorelease(obj); } -id objc_retainAutoreleasedReturnValue(id obj) +PUBLIC id objc_retainAutoreleasedReturnValue(id obj) { // If the previous object was released with objc_autoreleaseReturnValue() // just before return, then it will not have actually been autoreleased. @@ -567,36 +567,36 @@ id objc_retainAutoreleasedReturnValue(id obj) return objc_retain(obj); } -id objc_retain(id obj) +PUBLIC id objc_retain(id obj) { if (nil == obj) { return nil; } return retain(obj); } -id objc_retainAutorelease(id obj) +PUBLIC id objc_retainAutorelease(id obj) { return objc_autorelease(objc_retain(obj)); } -id objc_retainAutoreleaseReturnValue(id obj) +PUBLIC id objc_retainAutoreleaseReturnValue(id obj) { if (nil == obj) { return obj; } return objc_autoreleaseReturnValue(retain(obj)); } -id objc_retainBlock(id b) +PUBLIC id objc_retainBlock(id b) { return _Block_copy(b); } -void objc_release(id obj) +PUBLIC void objc_release(id obj) { if (nil == obj) { return; } release(obj); } -id objc_storeStrong(id *addr, id value) +PUBLIC id objc_storeStrong(id *addr, id value) { value = objc_retain(value); id oldValue = *addr; @@ -697,7 +697,7 @@ static inline BOOL weakRefRelease(WeakRef *ref) void* block_load_weak(void *block); -id objc_storeWeak(id *addr, id obj) +PUBLIC id objc_storeWeak(id *addr, id obj) { LOCK_FOR_SCOPE(&weakRefLock); WeakRef *oldRef; @@ -787,7 +787,7 @@ id objc_storeWeak(id *addr, id obj) return obj; } -BOOL objc_delete_weak_refs(id obj) +PUBLIC BOOL objc_delete_weak_refs(id obj) { LOCK_FOR_SCOPE(&weakRefLock); if (objc_test_class_flag(classForObject(obj), objc_class_flag_fast_arc)) @@ -797,7 +797,7 @@ BOOL objc_delete_weak_refs(id obj) // have done so in between this thread's decrementing the reference // count and its acquiring the lock. In this case, report failure. uintptr_t *refCount = ((uintptr_t*)obj) - 1; - if ((long)((__sync_fetch_and_add(refCount, 0) & refcount_mask)) < 0) + if ((long)((__sync_fetch_and_add(refCount, 0) & refcount_mask)) >= 0) { return NO; } @@ -805,13 +805,15 @@ BOOL objc_delete_weak_refs(id obj) WeakRef *oldRef = weak_ref_table_get(weakRefs, obj); if (0 != oldRef) { - // Zero the object pointer. This prevents any other weak - // accesses from loading from this. - oldRef->obj = nil; // The address of obj is likely to be reused, so remove it from // the table so that we don't accidentally alias weak // references weak_ref_remove(weakRefs, obj); + // Zero the object pointer. This prevents any other weak + // accesses from loading from this. This must be done after + // removing the ref from the table, because the compare operation + // tests the obj field. + oldRef->obj = nil; // If the weak reference count is zero, then we should have // already removed this. assert(oldRef->weak_count > 0); @@ -819,7 +821,7 @@ BOOL objc_delete_weak_refs(id obj) return YES; } -id objc_loadWeakRetained(id* addr) +PUBLIC id objc_loadWeakRetained(id* addr) { LOCK_FOR_SCOPE(&weakRefLock); id obj; @@ -857,12 +859,12 @@ id objc_loadWeakRetained(id* addr) return objc_retain(obj); } -id objc_loadWeak(id* object) +PUBLIC id objc_loadWeak(id* object) { return objc_autorelease(objc_loadWeakRetained(object)); } -void objc_copyWeak(id *dest, id *src) +PUBLIC void objc_copyWeak(id *dest, id *src) { // Don't retain or release. While the weak ref lock is held, we know that // the object can't be deallocated, so we just move the value and update @@ -884,7 +886,7 @@ void objc_copyWeak(id *dest, id *src) } } -void objc_moveWeak(id *dest, id *src) +PUBLIC void objc_moveWeak(id *dest, id *src) { // Don't retain or release. While the weak ref lock is held, we know that // the object can't be deallocated, so we just move the value and update @@ -902,12 +904,12 @@ void objc_moveWeak(id *dest, id *src) } } -void objc_destroyWeak(id* obj) +PUBLIC void objc_destroyWeak(id* obj) { objc_storeWeak(obj, nil); } -id objc_initWeak(id *object, id value) +PUBLIC id objc_initWeak(id *object, id value) { *object = nil; return objc_storeWeak(object, value); diff --git a/asmconstants.h b/asmconstants.h index 589e94c..d5f9559 100644 --- a/asmconstants.h +++ b/asmconstants.h @@ -4,6 +4,13 @@ #define SHIFT_OFFSET 0 #define DATA_OFFSET 8 #define SLOT_OFFSET 0 +#elif defined(_WIN64) +// long is 32 bits on Win64, so struct objc_class is smaller. All other offsets are the same. +#define DTABLE_OFFSET 56 +#define SMALLOBJ_BITS 3 +#define SHIFT_OFFSET 0 +#define DATA_OFFSET 8 +#define SLOT_OFFSET 0 #else #define DTABLE_OFFSET 32 #define SMALLOBJ_BITS 1 diff --git a/associate.m b/associate.m index 6c502eb..c895b55 100644 --- a/associate.m +++ b/associate.m @@ -388,6 +388,7 @@ PRIVATE void gc_setTypeForClass(Class cls, void *type) list->gc_type = type; } +PUBLIC int objc_sync_enter(id object) { if ((object == 0) || isSmallObject(object)) { return 0; } @@ -396,6 +397,7 @@ int objc_sync_enter(id object) return 0; } +PUBLIC int objc_sync_exit(id object) { if ((object == 0) || isSmallObject(object)) { return 0; } diff --git a/block_to_imp.c b/block_to_imp.c index 4d9e9d5..b43a1b0 100644 --- a/block_to_imp.c +++ b/block_to_imp.c @@ -8,9 +8,11 @@ #include #include #include +#ifndef _WIN32 #include #include #include +#endif #include "objc/runtime.h" #include "objc/blocks_runtime.h" #include "blocks_runtime.h" @@ -108,7 +110,12 @@ static id invalid(id self, SEL _cmd) static struct trampoline_set *alloc_trampolines(char *start, char *end) { struct trampoline_set *metadata = calloc(1, sizeof(struct trampoline_set)); - metadata->buffers = valloc(sizeof(struct trampoline_buffers)); + metadata->buffers = +#ifdef _WIN32 + VirtualAlloc(NULL, sizeof(struct trampoline_buffers), MEM_COMMIT, PAGE_READWRITE); +#else + valloc(sizeof(struct trampoline_buffers)); +#endif for (int i=0 ; ibuffers->headers[i].fnptr = (void(*)(void))invalid; @@ -117,7 +124,12 @@ static struct trampoline_set *alloc_trampolines(char *start, char *end) memcpy(block, start, end-start); } metadata->buffers->headers[HEADERS_PER_PAGE-1].block = NULL; +#ifdef _WIN32 + DWORD ignored; + VirtualProtect(metadata->buffers->rx_buffer, PAGE_SIZE, PAGE_EXECUTE_READ, &ignored); +#else mprotect(metadata->buffers->rx_buffer, PAGE_SIZE, PROT_READ | PROT_EXEC); +#endif clear_cache(metadata->buffers->rx_buffer, &metadata->buffers->rx_buffer[PAGE_SIZE]); return metadata; } diff --git a/blocks_runtime.m b/blocks_runtime.m index 74e2163..bda2f00 100644 --- a/blocks_runtime.m +++ b/blocks_runtime.m @@ -42,7 +42,7 @@ static void *_HeapBlockByRef = (void*)1; /** * Returns the Objective-C type encoding for the block. */ -const char *block_getType_np(const void *b) +PUBLIC const char *block_getType_np(const void *b) { const struct Block_layout *block = b; if ((NULL == block) || !(block->flags & BLOCK_HAS_SIGNATURE)) @@ -111,7 +111,7 @@ static int cas(void *ptr, void *old, void *new) * the other choices which are mutually exclusive. Only in a Block copy helper * will one see BLOCK_FIELD_IS_BYREF. */ -void _Block_object_assign(void *destAddr, const void *object, const int flags) +PUBLIC void _Block_object_assign(void *destAddr, const void *object, const int flags) { //printf("Copying %x to %x with flags %x\n", object, destAddr, flags); // FIXME: Needs to be implemented @@ -190,7 +190,7 @@ void _Block_object_assign(void *destAddr, const void *object, const int flags) * The same flags used in the copy helper should be used for each call * generated to this function: */ -void _Block_object_dispose(const void *object, const int flags) +PUBLIC void _Block_object_dispose(const void *object, const int flags) { // FIXME: Needs to be implemented //if(flags & BLOCK_FIELD_IS_WEAK) @@ -235,7 +235,7 @@ void _Block_object_dispose(const void *object, const int flags) // Copy a block to the heap if it's still on the stack or increments its retain count. -void *_Block_copy(const void *src) +PUBLIC void *_Block_copy(const void *src) { if (NULL == src) { return NULL; } struct Block_layout *self = (struct Block_layout*)src; @@ -269,7 +269,7 @@ void *_Block_copy(const void *src) } // Release a block and frees the memory when the retain count hits zero. -void _Block_release(const void *src) +PUBLIC void _Block_release(const void *src) { if (NULL == src) { return; } struct Block_layout *self = (struct Block_layout*)src; diff --git a/caps.c b/caps.c index 294b217..e54ee6e 100644 --- a/caps.c +++ b/caps.c @@ -34,7 +34,7 @@ static const int32_t caps = #endif 0; -int objc_test_capability(int x) +PUBLIC int objc_test_capability(int x) { if (x >= 32) { return 0; } if (caps & (1<dtable != uninstalled_dtable); } +PUBLIC int objc_sync_enter(id object); +PUBLIC int objc_sync_exit(id object); /** * Returns the dtable for a given class. If we are currently in an +initialize diff --git a/eh_win32_msvc.cc b/eh_win32_msvc.cc index 7c7ba63..e8463d1 100644 --- a/eh_win32_msvc.cc +++ b/eh_win32_msvc.cc @@ -6,6 +6,11 @@ #include "objc/runtime.h" #include "visibility.h" +#include +#define RtlAddGrowableFunctionTable ClangIsConfusedByTypedefReturnTypes +#include + + #ifndef __has_builtin #define __has_builtin(x) 0 #endif @@ -24,33 +29,32 @@ struct _MSVC_TypeDescriptor struct _MSVC_CatchableType { unsigned int flags; - _MSVC_TypeDescriptor* type; + unsigned long type; int mdisp; int pdisp; int vdisp; int size; - void* copyFunction; + unsigned long copyFunction; }; struct _MSVC_CatchableTypeArray { int count; - _MSVC_CatchableType* types[0]; + unsigned long types[0]; }; struct _MSVC_ThrowInfo { unsigned int attributes; - void* pfnUnwind; - void* pfnForwardCompat; - _MSVC_CatchableTypeArray* pCatchableTypeArray; + unsigned long pfnUnwind; + unsigned long pfnForwardCompat; + unsigned long pCatchableTypeArray; }; #if defined(_WIN64) -extern "C" int __ImageBase; -#define IMAGE_RELATIVE(ptr) ((decltype(ptr))(ptr ? ((uintptr_t)ptr - (uintptr_t)&__ImageBase) : (uintptr_t)nullptr)) +#define IMAGE_RELATIVE(ptr, base) (static_cast((ptr ? ((uintptr_t)ptr - (uintptr_t)base) : (uintptr_t)nullptr))) #else -#define IMAGE_RELATIVE(ptr) (ptr) +#define IMAGE_RELATIVE(ptr, base) reinterpret_cast((ptr)) #endif extern "C" void __stdcall _CxxThrowException(void*, _MSVC_ThrowInfo*); @@ -60,8 +64,11 @@ namespace static std::string mangleObjcObject() { - // This mangled name doesn't vary based on bitness. +#if defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ == 8 + return ".PEAUobjc_object@@"; +#else return ".PAUobjc_object@@"; +#endif } static std::string mangleStructNamed(const char* className) @@ -70,13 +77,15 @@ static std::string mangleStructNamed(const char* className) // .PAUxxx@@ = ?? struct xxx * `RTTI Type Descriptor' // 64-bit: // .PEAUxxx@@ = ?? struct xxx * __ptr64 `RTTI Type Descriptor' - return + //return + auto r = #if defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ == 8 std::string(".PEAU") + #else std::string(".PAU") + #endif className + "@@"; + return r; } void fillCatchableType(_MSVC_CatchableType* exceptType) @@ -86,13 +95,18 @@ void fillCatchableType(_MSVC_CatchableType* exceptType) exceptType->pdisp = -1; exceptType->vdisp = 0; exceptType->size = sizeof(id); - exceptType->copyFunction = nullptr; + exceptType->copyFunction = 0; } } // +struct X {}; +PUBLIC extern "C" void objc_exception_rethrow(void* exc); + PUBLIC extern "C" void objc_exception_throw(id object) { + // Base used for image-relative addresses. + char x; // This is the base vtable for all RTTI entries static const void* typeid_vtable = *(void**)&typeid(void *); @@ -118,7 +132,7 @@ PUBLIC extern "C" void objc_exception_throw(id object) size_t typeCount = 1; // Get count of all types in exception - for (Class cls = object_getClass(object); cls != nil; cls = class_getSuperclass(cls), ++typeCount) + for (Class cls = object_getClass(object); cls != Nil; cls = class_getSuperclass(cls), ++typeCount) ; // Unfortunately we can't put this in a real function since the alloca has to be in this stack frame: @@ -134,37 +148,66 @@ PUBLIC extern "C" void objc_exception_throw(id object) // Add exception type and all base types to throw information size_t curTypeIndex = 0; - for (Class cls = object_getClass(object); cls != nil; cls = class_getSuperclass(cls)) + for (Class cls = object_getClass(object); cls != Nil; cls = class_getSuperclass(cls)) { auto exceptType = (_MSVC_CatchableType*)_alloca(sizeof(_MSVC_CatchableType)); fillCatchableType(exceptType); auto mangledName = mangleStructNamed(class_getName(cls)); - CREATE_TYPE_DESCRIPTOR(exceptType->type, mangledName); - exceptType->type = IMAGE_RELATIVE(exceptType->type); - exceptTypes->types[curTypeIndex++] = IMAGE_RELATIVE(exceptType); + _MSVC_TypeDescriptor *ty; + CREATE_TYPE_DESCRIPTOR(ty, mangledName); + exceptType->type = IMAGE_RELATIVE(ty, &x); + exceptTypes->types[curTypeIndex++] = IMAGE_RELATIVE(exceptType, &x); } // Add id (struct objc_object*) auto exceptType = (_MSVC_CatchableType*)_alloca(sizeof(_MSVC_CatchableType)); fillCatchableType(exceptType); auto idName = mangleObjcObject(); - CREATE_TYPE_DESCRIPTOR(exceptType->type, idName); - exceptType->type = IMAGE_RELATIVE(exceptType->type); - exceptTypes->types[curTypeIndex++] = IMAGE_RELATIVE(exceptType); + _MSVC_TypeDescriptor *ty; + CREATE_TYPE_DESCRIPTOR(ty, idName); + exceptType->type = IMAGE_RELATIVE(ty, &x); + exceptTypes->types[curTypeIndex++] = IMAGE_RELATIVE(exceptType, &x); _MSVC_ThrowInfo ti = { 0, // attributes - NULL, // pfnUnwind - NULL, // pfnForwardCompat - IMAGE_RELATIVE(exceptTypes) // pCatchableTypeArray + 0, // pfnUnwind + 0, // pfnForwardCompat + IMAGE_RELATIVE(exceptTypes, &x) // pCatchableTypeArray }; - _CxxThrowException(&object, &ti); +# define EH_EXCEPTION_NUMBER ('msc' | 0xE0000000) +# define EH_MAGIC_NUMBER1 0x19930520 +# define EXCEPTION_NONCONTINUABLE 0x1 + EXCEPTION_RECORD exception; + exception.ExceptionCode = EH_EXCEPTION_NUMBER; + exception.ExceptionFlags = EXCEPTION_NONCONTINUABLE; + exception.ExceptionRecord = nullptr; + exception.ExceptionAddress = nullptr; + exception.NumberParameters = 4; + exception.ExceptionInformation[0] = EH_MAGIC_NUMBER1; + exception.ExceptionInformation[1] = reinterpret_cast(&object); + exception.ExceptionInformation[2] = reinterpret_cast(&ti); + exception.ExceptionInformation[3] = reinterpret_cast(&x); + + + RtlRaiseException(&exception); __builtin_unreachable(); } + PUBLIC extern "C" void objc_exception_rethrow(void* exc) { _CxxThrowException(nullptr, nullptr); __builtin_unreachable(); } + +// DO NOT COMMIT THIS! +// It's just here to get things to build while I work on EH support +PUBLIC extern "C" void *objc_begin_catch(void* exc) +{ + return exc; +} +PUBLIC extern "C" void *objc_end_catch(void* exc) +{ + return exc; +} diff --git a/encoding2.c b/encoding2.c index 2d5dde0..ee03f4d 100644 --- a/encoding2.c +++ b/encoding2.c @@ -8,6 +8,10 @@ #include "method.h" #include "visibility.h" +#ifdef max +# undef max +#endif + size_t objc_alignof_type (const char *type); // It would be so nice if this works, but in fact it returns nonsense: diff --git a/hash_table.h b/hash_table.h index efa5cf6..1c284d6 100644 --- a/hash_table.h +++ b/hash_table.h @@ -18,7 +18,6 @@ * which has a static size. */ #include "lock.h" -#include #include #include #include diff --git a/loader.c b/loader.c index c62684a..cdb435b 100644 --- a/loader.c +++ b/loader.c @@ -165,7 +165,10 @@ struct objc_init struct nsstr *strings_end; }; // end: objc_init + +#ifdef DEBUG_LOADING #include +#endif static enum { LegacyABI, @@ -175,7 +178,7 @@ static enum { void registerProtocol(Protocol *proto); -void __objc_load(struct objc_init *init) +PUBLIC void __objc_load(struct objc_init *init) { init_runtime(); #ifdef DEBUG_LOADING @@ -293,7 +296,7 @@ void __objc_load(struct objc_init *init) } #ifdef OLDABI_COMPAT -void __objc_exec_class(struct objc_module_abi_8 *module) +PUBLIC void __objc_exec_class(struct objc_module_abi_8 *module) { init_runtime(); diff --git a/objc/Availability.h b/objc/Availability.h index 0bdc7cd..771256c 100644 --- a/objc/Availability.h +++ b/objc/Availability.h @@ -2,6 +2,7 @@ #pragma clang system_header #endif +#include "objc-visibility.h" #ifdef STRICT_MACOS_X # define OBJC_NONPORTABLE __attribute__((error("Function not supported by the Apple runtime"))) diff --git a/objc/blocks_runtime.h b/objc/blocks_runtime.h index 3834f54..49702f4 100644 --- a/objc/blocks_runtime.h +++ b/objc/blocks_runtime.h @@ -13,9 +13,9 @@ #define BLOCKS_EXPORT extern #endif -BLOCKS_EXPORT void *_Block_copy(const void *); -BLOCKS_EXPORT void _Block_release(const void *); -BLOCKS_EXPORT const char *block_getType_np(const void *b) OBJC_NONPORTABLE; +PUBLIC BLOCKS_EXPORT void *_Block_copy(const void *); +PUBLIC BLOCKS_EXPORT void _Block_release(const void *); +PUBLIC BLOCKS_EXPORT const char *block_getType_np(const void *b) OBJC_NONPORTABLE; #define Block_copy(x) ((__typeof(x))_Block_copy((const void *)(x))) #define Block_release(x) _Block_release((const void *)(x)) diff --git a/objc/capabilities.h b/objc/capabilities.h index 07c96cb..d09cb9d 100644 --- a/objc/capabilities.h +++ b/objc/capabilities.h @@ -136,6 +136,7 @@ extern "C" { * Run time feature test. This function returns 1 if the runtime supports the * specified feature or 0 if it does not. */ +PUBLIC int objc_test_capability(int x) OBJC_NONPORTABLE; #ifdef __cplusplus } diff --git a/objc/hooks.h b/objc/hooks.h index 0b484d5..8b56a1d 100644 --- a/objc/hooks.h +++ b/objc/hooks.h @@ -1,6 +1,7 @@ #if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__) #pragma clang system_header #endif +#include "objc-visibility.h" #ifdef __cplusplus extern "C" { @@ -13,7 +14,7 @@ extern "C" { #ifndef OBJC_HOOK -#define OBJC_HOOK extern +#define OBJC_HOOK PUBLIC extern #endif struct objc_category; /** @@ -34,17 +35,17 @@ OBJC_HOOK void (*_objc_load_callback)(Class cls, struct objc_category *category) * The hook used for fast proxy lookups. This takes an object and a selector * and returns the instance that the message should be forwarded to. */ -extern id (*objc_proxy_lookup)(id receiver, SEL op); +OBJC_HOOK id (*objc_proxy_lookup)(id receiver, SEL op); /** * New runtime forwarding hook. This is no longer used, but is retained to * prevent errors at link time. */ -extern struct objc_slot *(*__objc_msg_forward3)(id, SEL) OBJC_DEPRECATED; +OBJC_HOOK struct objc_slot *(*__objc_msg_forward3)(id, SEL) OBJC_DEPRECATED; /** * Forwarding hook. Takes an object and a selector and returns a method that * handles the forwarding. */ -extern IMP (*__objc_msg_forward2)(id, SEL); +OBJC_HOOK IMP (*__objc_msg_forward2)(id, SEL); /** * Hook defined for handling unhandled exceptions. If the unwind library * reaches the end of the stack without finding a handler then this hook is @@ -66,7 +67,7 @@ OBJC_HOOK Class (*_objc_class_for_boxing_foreign_exception)(int64_t exceptionCla * receiver. This should return the slot to use instead, although it may throw * an exception or perform some other action. */ -extern IMP (*_objc_selector_type_mismatch2)(Class cls, +OBJC_HOOK IMP (*_objc_selector_type_mismatch2)(Class cls, SEL selector, struct objc_slot2 *result); /** * Legacy hook for when selector types do not match. This is only called @@ -108,7 +109,7 @@ typedef IMP (*objc_tracing_hook)(id, SEL, IMP, int, void*); /** * Registers a tracing hook for a specified selector. */ -int objc_registerTracingHook(SEL, objc_tracing_hook); +PUBLIC int objc_registerTracingHook(SEL, objc_tracing_hook); #ifdef __cplusplus } diff --git a/objc/message.h b/objc/message.h index e84af2f..f1395c3 100644 --- a/objc/message.h +++ b/objc/message.h @@ -1,6 +1,7 @@ #if defined(__clang__) #pragma clang system_header #endif +#include "objc-visibility.h" #ifndef _OBJC_MESSAGE_H_ #define _OBJC_MESSAGE_H_ @@ -22,6 +23,7 @@ * systems even within the same architecture, so take great care if using this * function for small (two integer) structures. */ +PUBLIC id objc_msgSend(id self, SEL _cmd, ...); /** * Standard message sending function. This function must be cast to the @@ -38,6 +40,7 @@ id objc_msgSend(id self, SEL _cmd, ...); * architecture, so take great care if using this function for small (two * integer) structures. */ +PUBLIC #ifdef __cplusplus id objc_msgSend_stret(id self, SEL _cmd, ...); #else @@ -55,6 +58,7 @@ void objc_msgSend_stret(id self, SEL _cmd, ...); * This version of the function is used for all messages that return floating * point values. */ +PUBLIC long double objc_msgSend_fpret(id self, SEL _cmd, ...); #endif diff --git a/objc/objc-arc.h b/objc/objc-arc.h index 14f7d00..a44e9b4 100644 --- a/objc/objc-arc.h +++ b/objc/objc-arc.h @@ -1,6 +1,7 @@ #if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__) #pragma clang system_header #endif +#include "objc-visibility.h" #ifndef __OBJC_ARC_INCLUDED__ #define __OBJC_ARC_INCLUDED__ @@ -12,90 +13,90 @@ extern "C" { /** * Autoreleases the argument. Equivalent to [obj autorelease]. */ -id objc_autorelease(id obj); +PUBLIC id objc_autorelease(id obj); /** * Autoreleases a return value. This is equivalent to [obj autorelease], but * may also store the object somewhere where it can be quickly removed without * the need for any message sending. */ -id objc_autoreleaseReturnValue(id obj); +PUBLIC id objc_autoreleaseReturnValue(id obj); /** * Initializes object as a weak pointer and stores value in it, or nil if value * has already begun deallocation. */ -id objc_initWeak(id *object, id value); +PUBLIC id objc_initWeak(id *object, id value); /** * Loads the object. Returns nil if the object stored at this address has * already begun deallocation. */ -id objc_loadWeak(id* object); +PUBLIC id objc_loadWeak(id* object); /** * Loads a weak value and retains it. */ -id objc_loadWeakRetained(id* obj); +PUBLIC id objc_loadWeakRetained(id* obj); /** * Retains the argument. Equivalent to [obj retain]. */ -id objc_retain(id obj); +PUBLIC id objc_retain(id obj); /** * Retains the argument, assuming that the argument is a normal object and has * its reference count managed by the runtime. * This is intended to implement `-retain` in ARC-compatible root classes. */ -id objc_retain_fast_np(id obj) OBJC_NONPORTABLE; +PUBLIC id objc_retain_fast_np(id obj) OBJC_NONPORTABLE; /** * Retains and autoreleases an object. Equivalent to [[obj retain] autorelease]. */ -id objc_retainAutorelease(id obj); +PUBLIC id objc_retainAutorelease(id obj); /** * Retains and releases a return value. Equivalent to * objc_retain(objc_autoreleaseReturnValue(obj)). */ -id objc_retainAutoreleaseReturnValue(id obj); +PUBLIC id objc_retainAutoreleaseReturnValue(id obj); /** * Retains a return value that has previously been autoreleased and returned. * This is equivalent to objc_retainAutoreleaseReturnValue(), but may support a * fast path, skipping the autorelease pool entirely. */ -id objc_retainAutoreleasedReturnValue(id obj); +PUBLIC id objc_retainAutoreleasedReturnValue(id obj); /** * Retains a block. */ -id objc_retainBlock(id b); +PUBLIC id objc_retainBlock(id b); /** * Stores value in addr. This first retains value, then releases the old value * at addr, and stores the retained value in the address. */ -id objc_storeStrong(id *addr, id value); +PUBLIC id objc_storeStrong(id *addr, id value); /** * Stores obj in zeroing weak pointer addr. If obj has begun deallocation, * then this stores nil. */ -id objc_storeWeak(id *addr, id obj); +PUBLIC id objc_storeWeak(id *addr, id obj); /** * Allocates an autorelease pool and pushes it onto the top of the autorelease * pool stack. Note that the returned autorelease pool is not required to be * an object. */ -void *objc_autoreleasePoolPush(void); +PUBLIC void *objc_autoreleasePoolPush(void); /** * Pops the specified autorelease pool from the stack, sending release messages * to every object that has been autreleased since the pool was created. */ -void objc_autoreleasePoolPop(void *pool); +PUBLIC void objc_autoreleasePoolPop(void *pool); /** * Initializes dest as a weak pointer and stores the value stored in src into * it. */ -void objc_copyWeak(id *dest, id *src); +PUBLIC void objc_copyWeak(id *dest, id *src); /** * Destroys addr as a weak pointer. */ -void objc_destroyWeak(id* addr); +PUBLIC void objc_destroyWeak(id* addr); /** * Equivalent to objc_copyWeak(), but may also set src to nil. */ -void objc_moveWeak(id *dest, id *src); +PUBLIC void objc_moveWeak(id *dest, id *src); /** * Releases the argument, assuming that the argument is a normal object and has * its reference count managed by the runtime. If the retain count reaches @@ -105,7 +106,7 @@ void objc_moveWeak(id *dest, id *src); * This is intended to implement `-release` in ARC-compatible root * classes. */ -void objc_release_fast_np(id obj) OBJC_NONPORTABLE; +PUBLIC void objc_release_fast_np(id obj) OBJC_NONPORTABLE; /** * Releases the argument, assuming that the argument is a normal object and has * its reference count managed by the runtime. If the retain count reaches @@ -115,15 +116,15 @@ void objc_release_fast_np(id obj) OBJC_NONPORTABLE; * This is intended to implement `NSDecrementExtraRefCountWasZero` for use with * ARC-compatible classes. */ -BOOL objc_release_fast_no_destroy_np(id obj) OBJC_NONPORTABLE; +PUBLIC BOOL objc_release_fast_no_destroy_np(id obj) OBJC_NONPORTABLE; /** * Returns the retain count of an object. */ -size_t object_getRetainCount_np(id obj) OBJC_NONPORTABLE; +PUBLIC size_t object_getRetainCount_np(id obj) OBJC_NONPORTABLE; /** * Releases an object. Equivalent to [obj release]. */ -void objc_release(id obj); +PUBLIC void objc_release(id obj); /** * Mark the object as about to begin deallocation. All subsequent reads of * weak pointers will return 0. This function should be called in -release, @@ -133,16 +134,16 @@ void objc_release(id obj); * * Nonstandard extension. */ -BOOL objc_delete_weak_refs(id obj); +PUBLIC BOOL objc_delete_weak_refs(id obj); /** * Returns the total number of objects in the ARC-managed autorelease pool. */ -unsigned long objc_arc_autorelease_count_np(void); +PUBLIC unsigned long objc_arc_autorelease_count_np(void); /** * Returns the total number of times that an object has been autoreleased in * this thread. */ -unsigned long objc_arc_autorelease_count_for_object_np(id); +PUBLIC unsigned long objc_arc_autorelease_count_for_object_np(id); #ifdef __cplusplus } diff --git a/objc/runtime.h b/objc/runtime.h index 0607625..ca19bf1 100644 --- a/objc/runtime.h +++ b/objc/runtime.h @@ -1,6 +1,7 @@ #if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__) #pragma clang system_header #endif +#include "objc-visibility.h" #ifndef __LIBOBJC_RUNTIME_H_INCLUDED__ #define __LIBOBJC_RUNTIME_H_INCLUDED__ @@ -124,7 +125,7 @@ typedef struct objc_method *Method; # ifdef STRICT_APPLE_COMPATIBILITY typedef signed char BOOL; # else -# ifdef __vxworks +# if defined(__vxworks) || defined(_WIN32) typedef int BOOL; # else typedef unsigned char BOOL; @@ -224,6 +225,7 @@ typedef struct * registered by the runtime. The alignment must be the base-2 logarithm of * the alignment requirement and the types should be an Objective-C type encoding. */ +PUBLIC BOOL class_addIvar(Class cls, const char *name, size_t size, @@ -233,11 +235,13 @@ BOOL class_addIvar(Class cls, /** * Adds a method to the class. */ +PUBLIC BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types); /** * Adds a protocol to the class. */ +PUBLIC BOOL class_addProtocol(Class cls, Protocol *protocol); /** @@ -245,6 +249,7 @@ BOOL class_addProtocol(Class cls, Protocol *protocol); * name are regarded as equivalent, even if they have different methods. This * behaviour will change in a future version. */ +PUBLIC BOOL class_conformsToProtocol(Class cls, Protocol *protocol); /** @@ -252,6 +257,7 @@ BOOL class_conformsToProtocol(Class cls, Protocol *protocol); * the outCount argument is set to the number of instance variables returned. * The caller is responsible for freeing the returned buffer. */ +PUBLIC Ivar* class_copyIvarList(Class cls, unsigned int *outCount); /** @@ -259,6 +265,7 @@ Ivar* class_copyIvarList(Class cls, unsigned int *outCount); * outCount argument is set to the number of methods returned. The caller is * responsible for freeing the returned buffer. */ +PUBLIC Method * class_copyMethodList(Class cls, unsigned int *outCount); /** @@ -266,6 +273,7 @@ Method * class_copyMethodList(Class cls, unsigned int *outCount); * the outCount argument is set to the number of declared properties returned. * The caller is responsible for freeing the returned buffer. */ +PUBLIC objc_property_t* class_copyPropertyList(Class cls, unsigned int *outCount); /** @@ -273,11 +281,13 @@ objc_property_t* class_copyPropertyList(Class cls, unsigned int *outCount); * outCount argument is set to the number of protocols returned. The caller is * responsible for freeing the returned buffer. */ +PUBLIC Protocol *__unsafe_unretained* class_copyProtocolList(Class cls, unsigned int *outCount); /** * Creates an instance of this class, allocating memory using malloc. */ +PUBLIC id class_createInstance(Class cls, size_t extraBytes); /** @@ -285,6 +295,7 @@ id class_createInstance(Class cls, size_t extraBytes); * class. This is an opaque data type and must be accessed with the method_*() * family of functions. */ +PUBLIC Method class_getClassMethod(Class aClass, SEL aSelector); /** @@ -292,6 +303,7 @@ Method class_getClassMethod(Class aClass, SEL aSelector); * this class. This is an opaque data type and must be accessed with the * ivar_*() family of functions. */ +PUBLIC Ivar class_getClassVariable(Class cls, const char* name); /** @@ -299,6 +311,7 @@ Ivar class_getClassVariable(Class cls, const char* name); * in this class. This is an opaque data type and must be accessed with the * method_*() family of functions. */ +PUBLIC Method class_getInstanceMethod(Class aClass, SEL aSelector); /** @@ -306,6 +319,7 @@ Method class_getInstanceMethod(Class aClass, SEL aSelector); * class's superclasses must be loaded before this call, or the result is * undefined with the non-fragile ABI. */ +PUBLIC size_t class_getInstanceSize(Class cls); /** @@ -313,22 +327,26 @@ size_t class_getInstanceSize(Class cls); * returning a pointer to the instance variable definition or a null * pointer if no instance variable of that name was found. */ +PUBLIC Ivar class_getInstanceVariable(Class cls, const char* name); /** * Sets the object value of a specified instance variable. */ +PUBLIC void object_setIvar(id object, Ivar ivar, id value); /** * Sets a named instance variable to the value specified by *value. Note that * the instance variable must be a pointer-sized quantity. */ +PUBLIC Ivar object_setInstanceVariable(id obj, const char *name, void *value); /** * Returns the value of the named instance variable. This should not be used * with instance variables that are not pointers. */ +PUBLIC id object_getIvar(id object, Ivar ivar); /** @@ -337,6 +355,7 @@ id object_getIvar(id object, Ivar ivar); * * Note that the instance variable must be a pointer-sized quantity. */ +PUBLIC Ivar object_getInstanceVariable(id obj, const char *name, void **outValue); /** @@ -344,54 +363,62 @@ Ivar object_getInstanceVariable(id obj, const char *name, void **outValue); * the receiver does not have a method corresponding to this message then this * function may return a runtime function that performs forwarding. */ +PUBLIC IMP class_getMethodImplementation(Class cls, SEL name); /** * Identical to class_getMethodImplementation(). */ +PUBLIC IMP class_getMethodImplementation_stret(Class cls, SEL name); /** * Returns the name of the class. This string is owned by the runtime and is * valid for (at least) as long as the class remains loaded. */ +PUBLIC const char * class_getName(Class cls); /** * Retrieves metadata about the property with the specified name. */ +PUBLIC objc_property_t class_getProperty(Class cls, const char *name); /** * Returns the superclass of the specified class. */ +PUBLIC Class class_getSuperclass(Class cls); /** * Returns the version of the class. Currently, the class version is not used * inside the runtime at all, however it may be used for the developer-mode ABI. */ +PUBLIC int class_getVersion(Class theClass); /** * Sets the version for this class. */ +PUBLIC void class_setVersion(Class theClass, int version); -OBJC_GNUSTEP_RUNTIME_UNSUPPORTED("Weak instance variables") +PUBLIC OBJC_GNUSTEP_RUNTIME_UNSUPPORTED("Weak instance variables") const char *class_getWeakIvarLayout(Class cls); /** * Returns whether the class is a metaclass. This can be used in conjunction * with object_getClass() for differentiating between objects and classes. */ +PUBLIC BOOL class_isMetaClass(Class cls); /** * Registers an alias for the class. Returns YES if the alias could be * registered successfully. */ -OBJC_NONPORTABLE +PUBLIC OBJC_NONPORTABLE BOOL class_registerAlias_np(Class cls, const char *alias); /** @@ -399,6 +426,7 @@ BOOL class_registerAlias_np(Class cls, const char *alias); * Objective-C runtime uses typed selectors, however the types of the selector * will be ignored and a new selector registered with the specified types. */ +PUBLIC IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types); /** @@ -407,17 +435,20 @@ IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types); * or more of the various forwarding mechanisms, then this will still return * NO. */ +PUBLIC BOOL class_respondsToSelector(Class cls, SEL sel); /** * Returns the instance variable layout of this class as an opaque list that * can be applied to other classes. */ +PUBLIC const char *class_getIvarLayout(Class cls); /** * Sets the class's instance variable layout. The layout argument must be a * value returned by class_getIvarLayout(). */ +PUBLIC void class_setIvarLayout(Class cls, const char *layout); /** @@ -425,26 +456,29 @@ void class_setIvarLayout(Class cls, const char *layout); * because modifying the superclass of a class at run time is a very complex * operation and this function is almost always used incorrectly. */ -__attribute__((deprecated)) +PUBLIC __attribute__((deprecated)) Class class_setSuperclass(Class cls, Class newSuper); -OBJC_GNUSTEP_RUNTIME_UNSUPPORTED("Weak instance variables") +PUBLIC OBJC_GNUSTEP_RUNTIME_UNSUPPORTED("Weak instance variables") void class_setWeakIvarLayout(Class cls, const char *layout); /** * Returns the name of an instance variable. */ +PUBLIC const char* ivar_getName(Ivar ivar); /** * Returns the offset of an instance variable. This value can be added to the * object pointer to get the address of the instance variable. */ +PUBLIC ptrdiff_t ivar_getOffset(Ivar ivar); /** * Returns the Objective-C type encoding of the instance variable. */ +PUBLIC const char* ivar_getTypeEncoding(Ivar ivar); /** @@ -453,12 +487,14 @@ const char* ivar_getTypeEncoding(Ivar ivar); * Objective-C method will be the self and _cmd parameters, so the returned * value will be "@" and ":" respectively. */ +PUBLIC char* method_copyArgumentType(Method method, unsigned int index); /** * Copies the type encoding of an argument of this method. The caller is * responsible for freeing the returned C string. */ +PUBLIC char* method_copyReturnType(Method method); /** @@ -466,6 +502,7 @@ char* method_copyReturnType(Method method); * expensive on the GNUstep runtime and its use is discouraged. It is * recommended that users call class_replaceMethod() instead. */ +PUBLIC void method_exchangeImplementations(Method m1, Method m2); /** @@ -475,11 +512,13 @@ void method_exchangeImplementations(Method m1, Method m2); * output string if there is enough space for the argument type and the NULL * terminator. Its use is therefore discouraged. */ +PUBLIC void method_getArgumentType(Method method, unsigned int index, char *dst, size_t dst_len); /** * Returns a pointer to the function used to implement this method. */ +PUBLIC IMP method_getImplementation(Method method); /** @@ -489,12 +528,14 @@ IMP method_getImplementation(Method method); * although calling method_getTypeEncoding() is faster if you just require the * types. */ +PUBLIC SEL method_getName(Method method); /** * Returns the number of arguments (including self and _cmd) that this method * expects. */ +PUBLIC unsigned method_getNumberOfArguments(Method method); /** @@ -504,6 +545,7 @@ unsigned method_getNumberOfArguments(Method method); * output string if there is enough space for the argument type and the NULL * terminator. Its use is therefore discouraged. */ +PUBLIC void method_getReturnType(Method method, char *dst, size_t dst_len); /** @@ -511,6 +553,7 @@ void method_getReturnType(Method method, char *dst, size_t dst_len); * runtime and will persist for (at least) as long as the class owning the * method is loaded. */ +PUBLIC const char * method_getTypeEncoding(Method method); /** @@ -518,6 +561,7 @@ const char * method_getTypeEncoding(Method method); * expensive with the GNUstep runtime and its use is discouraged. It is * recommended that you call class_replaceMethod() instead. */ +PUBLIC IMP method_setImplementation(Method method, IMP imp); /** @@ -526,6 +570,7 @@ IMP method_setImplementation(Method method, IMP imp); * used for class variables by adding instance variables to the returned * metaclass. */ +PUBLIC Class objc_allocateClassPair(Class superclass, const char *name, size_t extraBytes); /** @@ -533,6 +578,7 @@ Class objc_allocateClassPair(Class superclass, const char *name, size_t extraByt * attempts to send messages to instances of this class or its subclasses * result in undefined behaviour. */ +PUBLIC void objc_disposeClassPair(Class cls); /** @@ -541,6 +587,7 @@ void objc_disposeClassPair(Class cls); * loaded, it calls the _objc_lookup_class() callback to allow an external * library to load the module providing this class. */ +PUBLIC id objc_getClass(const char *name); /** @@ -549,18 +596,21 @@ id objc_getClass(const char *name); * is 0, it returns the total number of classes registered with the runtime. * Otherwise, it copies classes and returns the number copied. */ +PUBLIC int objc_getClassList(Class *buffer, int bufferLen); /** * Returns a copy of the list of all classes in the system. The caller is * responsible for freeing this list. The number of classes is returned in the * parameter. */ +PUBLIC Class *objc_copyClassList(unsigned int *outCount); /** * Returns the metaclass with the specified name. This is equivalent to * calling object_getClass() on the result of objc_getClass(). */ +PUBLIC id objc_getMetaClass(const char *name); /** @@ -568,17 +618,20 @@ id objc_getMetaClass(const char *name); * function should generally only be called early on in a program, to ensure * that all required libraries are loaded. */ +PUBLIC id objc_getRequiredClass(const char *name); /** * Looks up the class with the specified name, but does not invoke any * external lazy loading mechanisms. */ +PUBLIC id objc_lookUpClass(const char *name); /** * Returns the protocol with the specified name. */ +PUBLIC Protocol *objc_getProtocol(const char *name); /** * Allocates a new protocol. This returns NULL if a protocol with the same @@ -587,15 +640,18 @@ Protocol *objc_getProtocol(const char *name); * Protocols are immutable after they have been registered, so may only be * modified between calling this function and calling objc_registerProtocol(). */ +PUBLIC Protocol *objc_allocateProtocol(const char *name); /** * Registers a protocol with the runtime. After this point, the protocol may * not be modified. */ +PUBLIC void objc_registerProtocol(Protocol *proto); /** * Adds a method to the protocol. */ +PUBLIC void protocol_addMethodDescription(Protocol *aProtocol, SEL name, const char *types, @@ -604,10 +660,12 @@ void protocol_addMethodDescription(Protocol *aProtocol, /** * Adds a protocol to the protocol. */ +PUBLIC void protocol_addProtocol(Protocol *aProtocol, Protocol *addition); /** * Adds a property to the protocol. */ +PUBLIC void protocol_addProperty(Protocol *aProtocol, const char *name, const objc_property_attribute_t *attributes, @@ -622,6 +680,7 @@ void protocol_addProperty(Protocol *aProtocol, * adding instance variables and methods to it. A class can not have instance * variables added to it after objc_registerClassPair() has been called. */ +PUBLIC void objc_registerClassPair(Class cls); /** @@ -629,6 +688,7 @@ void objc_registerClassPair(Class cls); * object. This is a pointer to the storage specified with the extraBytes * parameter given when allocating an object. */ +PUBLIC void *object_getIndexedIvars(id obj); // FIXME: The GNU runtime has a version of this which omits the size parameter @@ -637,30 +697,35 @@ void *object_getIndexedIvars(id obj); /** * Free an object created with class_createInstance(). */ +PUBLIC id object_dispose(id obj); /** * Returns the class of the object. Note: the isa pointer should not be * accessed directly with the GNUstep runtime. */ +PUBLIC Class object_getClass(id obj); /** * Sets the class of the object. Note: the isa pointer should not be * accessed directly with the GNUstep runtime. */ +PUBLIC Class object_setClass(id obj, Class cls); /** * Returns the name of the class of the object. This is equivalent to calling * class_getName() on the result of object_getClass(). */ +PUBLIC const char *object_getClassName(id obj); /** * Returns the name of a specified property. */ +PUBLIC const char *property_getName(objc_property_t property); /** @@ -669,11 +734,13 @@ const char *property_getName(objc_property_t property); * description of the format for this string may be found in Apple's * Objective-C Runtime Programming Guide. */ +PUBLIC const char *property_getAttributes(objc_property_t property); /** * Returns an array of attributes for this property. */ +PUBLIC objc_property_attribute_t *property_copyAttributeList(objc_property_t property, unsigned int *outCount); /** @@ -681,6 +748,7 @@ objc_property_attribute_t *property_copyAttributeList(objc_property_t property, * that this only sets the property metadata. The property accessor methods * must already be created. */ +PUBLIC BOOL class_addProperty(Class cls, const char *name, const objc_property_attribute_t *attributes, @@ -690,6 +758,7 @@ BOOL class_addProperty(Class cls, * Replaces property metadata. If the property does not exist, then this is * equivalent to calling class_addProperty(). */ +PUBLIC void class_replaceProperty(Class cls, const char *name, const objc_property_attribute_t *attributes, @@ -698,12 +767,14 @@ void class_replaceProperty(Class cls, /** * Returns a copy of a single attribute. */ +PUBLIC char *property_copyAttributeValue(objc_property_t property, const char *attributeName); /** * Testswhether a protocol conforms to another protocol. */ +PUBLIC BOOL protocol_conformsToProtocol(Protocol *p, Protocol *other); /** @@ -711,6 +782,7 @@ BOOL protocol_conformsToProtocol(Protocol *p, Protocol *other); * the array in the variable pointed to by the last parameter. The caller is * responsible for freeing this array. */ +PUBLIC struct objc_method_description *protocol_copyMethodDescriptionList(Protocol *p, BOOL isRequiredMethod, BOOL isInstanceMethod, unsigned int *count); @@ -719,6 +791,7 @@ struct objc_method_description *protocol_copyMethodDescriptionList(Protocol *p, * stored in the variable pointed to by the last argument. The caller is * responsible for freeing the returned array. */ +PUBLIC objc_property_t *protocol_copyPropertyList(Protocol *p, unsigned int *count); /** @@ -726,6 +799,7 @@ objc_property_t *protocol_copyPropertyList(Protocol *p, unsigned int *count); * being stored in the variable pointed to by the last argument. The caller is * responsible for freeing the returned array. */ +PUBLIC objc_property_t *protocol_copyPropertyList2(Protocol *p, unsigned int *count, BOOL isRequiredProperty, BOOL isInstanceProperty); @@ -734,6 +808,7 @@ objc_property_t *protocol_copyPropertyList2(Protocol *p, unsigned int *count, * number of protocols in the array being returned via the last argument. The * caller is responsible for freeing this array. */ +PUBLIC Protocol *__unsafe_unretained*protocol_copyProtocolList(Protocol *p, unsigned int *count); /** @@ -744,11 +819,13 @@ Protocol *__unsafe_unretained*protocol_copyProtocolList(Protocol *p, unsigned in * * The caller is responsible for freeing the returned array. */ +PUBLIC Protocol *__unsafe_unretained*objc_copyProtocolList(unsigned int *outCount); /** * Returns the method description for the specified method within a given * protocol. */ +PUBLIC struct objc_method_description protocol_getMethodDescription(Protocol *p, SEL aSel, BOOL isRequiredMethod, BOOL isInstanceMethod); @@ -759,17 +836,20 @@ struct objc_method_description protocol_getMethodDescription(Protocol *p, * implementation and so its semantics may change in the future and this * runtime may diverge from Apple's. */ +PUBLIC const char *_protocol_getMethodTypeEncoding(Protocol *p, SEL aSel, BOOL isRequiredMethod, BOOL isInstanceMethod); /** * Returns the name of the specified protocol. */ +PUBLIC const char* protocol_getName(Protocol *p); /** * Returns the property metadata for the property with the specified name. */ +PUBLIC objc_property_t protocol_getProperty(Protocol *p, const char *name, BOOL isRequiredProperty, BOOL isInstanceProperty); @@ -779,6 +859,7 @@ objc_property_t protocol_getProperty(Protocol *p, const char *name, * which made not attempt to unique protocols (or even register them with the * runtime). */ +PUBLIC BOOL protocol_isEqual(Protocol *p, Protocol *other); /** @@ -786,21 +867,25 @@ BOOL protocol_isEqual(Protocol *p, Protocol *other); * the function (either a method or a forwarding hook) that should be called in * response to a given message. */ +PUBLIC IMP objc_msg_lookup(id, SEL) OBJC_NONPORTABLE; /** * The message lookup function used for messages sent to super in the GCC ABI. * This specifies both the class and the */ +PUBLIC IMP objc_msg_lookup_super(struct objc_super*, SEL) OBJC_NONPORTABLE; /** * Returns the name of the specified selector. */ +PUBLIC const char *sel_getName(SEL sel); /** * Registers a selector with the runtime. This is equivalent to sel_registerName(). */ +PUBLIC SEL sel_getUid(const char *selName); /** @@ -813,22 +898,26 @@ SEL sel_getUid(const char *selName); * both b and c are typed selectors with different types, then then the first * two will return YES, but the third case will return NO. */ +PUBLIC BOOL sel_isEqual(SEL sel1, SEL sel2); /** * Registers an untyped selector with the runtime. */ +PUBLIC SEL sel_registerName(const char *selName); /** * Register a typed selector. */ +PUBLIC SEL sel_registerTypedName_np(const char *selName, const char *types) OBJC_NONPORTABLE; /** * Returns the type encoding associated with a selector, or the empty string is * there is no such type. */ +PUBLIC const char *sel_getType_np(SEL aSel) OBJC_NONPORTABLE; /** @@ -839,6 +928,7 @@ const char *sel_getType_np(SEL aSel) OBJC_NONPORTABLE; * once with a relatively small on-stack buffer and then only call it again * with a heap-allocated buffer if there is not enough space. */ +PUBLIC unsigned sel_copyTypes_np(const char *selName, const char **types, unsigned count) OBJC_NONPORTABLE; /** @@ -849,12 +939,14 @@ unsigned sel_copyTypes_np(const char *selName, const char **types, unsigned coun * once with a relatively small on-stack buffer and then only call it again * with a heap-allocated buffer if there is not enough space. */ +PUBLIC unsigned sel_copyTypedSelectors_np(const char *selName, SEL *const sels, unsigned count) OBJC_NONPORTABLE; /** * New ABI lookup function. Receiver may be modified during lookup or proxy * forwarding and the sender may affect how lookup occurs. */ +PUBLIC extern struct objc_slot *objc_msg_lookup_sender(id *receiver, SEL selector, id sender) OBJC_NONPORTABLE OBJC_DEPRECATED; @@ -862,6 +954,7 @@ extern struct objc_slot *objc_msg_lookup_sender(id *receiver, SEL selector, id s * Deprecated function for accessing a slot without going via any forwarding * mechanisms. */ +PUBLIC extern struct objc_slot *objc_get_slot(Class, SEL) OBJC_NONPORTABLE OBJC_DEPRECATED; @@ -871,6 +964,7 @@ extern struct objc_slot *objc_get_slot(Class, SEL) * counter. If this value is equal to `objc_method_cache_version` then the * slot is safe to reuse without performing another lookup. */ +PUBLIC extern struct objc_slot2 *objc_get_slot2(Class, SEL, uint64_t*) OBJC_NONPORTABLE; @@ -880,12 +974,14 @@ extern struct objc_slot2 *objc_get_slot2(Class, SEL, uint64_t*) * counter. If this value is equal to `objc_method_cache_version` then the * slot is safe to reuse without performing another lookup. */ +PUBLIC extern struct objc_slot2 *objc_slot_lookup_version(id *receiver, SEL selector, uint64_t*) OBJC_NONPORTABLE; /** * Look up a slot, invoking any required forwarding mechanisms. */ +PUBLIC extern IMP objc_msg_lookup2(id *receiver, SEL selector) OBJC_NONPORTABLE; /** @@ -893,6 +989,7 @@ extern IMP objc_msg_lookup2(id *receiver, SEL selector) OBJC_NONPORTABLE; * pointer. If the class can be registered, then this returns YES. The second * argument specifies the bit pattern to use to identify the small object. */ +PUBLIC BOOL objc_registerSmallObjectClass_np(Class cls, uintptr_t classId); /** @@ -956,6 +1053,7 @@ typedef uintptr_t objc_AssociationPolicy; * Returns an object previously stored by calling objc_setAssociatedObject() * with the same arguments, or nil if none exists. */ +PUBLIC id objc_getAssociatedObject(id object, void *key); /** * Associates an object with another. This provides a mechanism for storing @@ -965,10 +1063,12 @@ id objc_getAssociatedObject(id object, void *key); * value may be any object, but must respond to -copy or -retain, and -release, * if an association policy of copy or retain is passed as the final argument. */ +PUBLIC void objc_setAssociatedObject(id object, void *key, id value, objc_AssociationPolicy policy); /** * Removes all associations from an object. */ +PUBLIC void objc_removeAssociatedObjects(id object); /** @@ -976,6 +1076,7 @@ void objc_removeAssociatedObjects(id object); * take an object pointer (self) as its first argument, and then the same * arguments as the method. */ +PUBLIC IMP imp_implementationWithBlock(void *block); /** * Returns the type encoding of an IMP that would be returned by passing the @@ -983,42 +1084,49 @@ IMP imp_implementationWithBlock(void *block); * block encoding for transforming to an IMP (it must take id as its first * argument). The caller is responsible for freeing the returned value. */ +PUBLIC char *block_copyIMPTypeEncoding_np(void*block); /** * Returns the block that was used in an IMP created by * imp_implementationWithBlock(). The result of calling this function with any * other IMP is undefined. */ +PUBLIC void *imp_getBlock(IMP anImp); /** * Removes a block that was converted to an IMP with * imp_implementationWithBlock(). The result of calling this function with any * other IMP is undefined. Returns YES on success, NO on failure. */ +PUBLIC BOOL imp_removeBlock(IMP anImp); /** * Adds a method to a specific object, This method will not be added to any * other instances of the same class. */ +PUBLIC BOOL object_addMethod_np(id object, SEL name, IMP imp, const char *types); /** * Replaces a method on a specific object, This method will not be added to * any other instances of the same class. */ +PUBLIC IMP object_replaceMethod_np(id object, SEL name, IMP imp, const char *types); /** * Creates a clone, in the JavaScript sense - an object which inherits both * associated references and methods from the original object. */ +PUBLIC id object_clone_np(id object); /** * Returns the prototype of the object if it was created with * object_clone_np(), or nil otherwise. */ +PUBLIC id object_getPrototype_np(id object); /** @@ -1039,6 +1147,7 @@ id object_getPrototype_np(id object); * This currently sets a global value. In the future, it may be configurable * on a per-thread basis. */ +PUBLIC int objc_set_apple_compatible_objcxx_exceptions(int newValue) OBJC_NONPORTABLE; diff --git a/objc_msgSend.S b/objc_msgSend.S index cbce6a0..57eb90c 100644 --- a/objc_msgSend.S +++ b/objc_msgSend.S @@ -15,4 +15,9 @@ #endif #ifdef __ELF__ .section .note.GNU-stack,"",%progbits +#elif defined(_WIN32) +.section .drectve,"yn" +.ascii " /EXPORT:objc_msgSend" +.ascii " /EXPORT:objc_msgSend_fpret" +.ascii " /EXPORT:objc_msgSend_stret" #endif diff --git a/objc_msgSend.x86-64.S b/objc_msgSend.x86-64.S index ebe5e5e..2f63d60 100644 --- a/objc_msgSend.x86-64.S +++ b/objc_msgSend.x86-64.S @@ -1,6 +1,24 @@ -.macro MSGSEND receiver, sel - .cfi_startproc # Start emitting unwind data. We +#ifdef _WIN64 +# define START_PROC(x) .seh_proc x +# define END_PROC(x) .seh_endproc +# define FRAME_OFFSET(x) .seh_stackalloc x +# define FIRST_ARGUMENT_STR "%rcx" +# define FIRST_ARGUMENT %rcx +# define SECOND_ARGUMENT %rdx +# define THIRD_ARGUMENT %r8 +#else +# define START_PROC(x) .cfi_startproc +# define END_PROC(x) .cfi_endproc +# define FRAME_OFFSET(x) .cfi_adjust_cfa_offset x +# define FIRST_ARGUMENT_STR "%rdi" +# define FIRST_ARGUMENT %rdi +# define SECOND_ARGUMENT %rsi +# define THIRD_ARGUMENT %rdx +#endif + +.macro MSGSEND fnname receiver, sel + START_PROC(\fnname) # Start emitting unwind data. We # don't actually care about any of # the stuff except the slow call, # because that's the only one that @@ -202,26 +220,26 @@ #rdi rsi rdx # We're (potentially) modifying the self argument with the lookup, so we don't want to be -.ifc "\receiver", "%rdi" - push %rdi - mov %rsp, %rdi - push %rsi # Save _cmd (not preserved across calls) - push %rdx +.ifc "\receiver", FIRST_ARGUMENT_STR + push FIRST_ARGUMENT + mov %rsp, FIRST_ARGUMENT + push SECOND_ARGUMENT # Save _cmd (not preserved across calls) + push THIRD_ARGUMENT .else - push %rdi # Save the sret pointer - push %rsi # Save self where it can be modified - mov %rsp, %rdi - push %rdx - mov %rdx, %rsi # move _cmd to where the callee expects it to be + push FIRST_ARGUMENT # Save the sret pointer + push SECOND_ARGUMENT # Save self where it can be modified + mov %rsp, FIRST_ARGUMENT + push THIRD_ARGUMENT + mov THIRD_ARGUMENT, SECOND_ARGUMENT # move _cmd to where the callee expects it to be .endif - .cfi_adjust_cfa_offset 0xD8 + FRAME_OFFSET(0xD8) call CDECL(slowMsgLookup) # Call the slow lookup function mov %rax, %r10 # Load the returned IMP - pop %rdx - pop %rsi - pop %rdi + pop THIRD_ARGUMENT + pop SECOND_ARGUMENT + pop FIRST_ARGUMENT movups 0x80(%rsp), %xmm0 movups 0x70(%rsp), %xmm1 @@ -244,16 +262,43 @@ lea CDECL(SmallObjectClasses)(%rip), %r11 mov (%r11, %r10, 8), %r10 jmp 1b - .cfi_endproc + END_PROC(\fnname) .endm +#ifdef _WIN64 +.text +.def objc_msgSend; +.scl 2; +.type 32; +.endef +.def objc_msgSend_fpret; +.scl 2; +.type 32; +.endef +.def objc_msgSend_stret; +.scl 2; +.type 32; +.endef +.globl CDECL(objc_msgSend_fpret) +TYPE_DIRECTIVE(CDECL(objc_msgSend_fpret), @function) +.globl CDECL(objc_msgSend) +TYPE_DIRECTIVE(CDECL(objc_msgSend), @function) +CDECL(objc_msgSend_fpret): +CDECL(objc_msgSend): + MSGSEND objc_msgSend, %rcx, %rdx +.globl CDECL(objc_msgSend_stret) +TYPE_DIRECTIVE(CDECL(objc_msgSend_stret), @function) +CDECL(objc_msgSend_stret): + MSGSEND objc_msgSend_stret, %rdx, %r8 +#else .globl CDECL(objc_msgSend) TYPE_DIRECTIVE(CDECL(objc_msgSend), @function) .globl CDECL(objc_msgSend_fpret) TYPE_DIRECTIVE(CDECL(objc_msgSend_fpret), @function) CDECL(objc_msgSend_fpret): CDECL(objc_msgSend): - MSGSEND %rdi, %rsi + MSGSEND objc_msgSend, %rdi, %rsi .globl CDECL(objc_msgSend_stret) TYPE_DIRECTIVE(CDECL(objc_msgSend_stret), @function) CDECL(objc_msgSend_stret): - MSGSEND %rsi, %rdx + MSGSEND objc_msgSend_stret, %rsi, %rdx +#endif diff --git a/properties.m b/properties.m index 17fb0f7..61acccc 100644 --- a/properties.m +++ b/properties.m @@ -4,7 +4,7 @@ #include #include #include -#include +#include "unistd.h" #include "class.h" #include "properties.h" #include "spinlock.h" @@ -18,6 +18,7 @@ PRIVATE int spinlocks[spinlock_count]; /** * Public function for getting a property. */ +PUBLIC id objc_getProperty(id obj, SEL _cmd, ptrdiff_t offset, BOOL isAtomic) { if (nil == obj) { return nil; } @@ -45,6 +46,7 @@ id objc_getProperty(id obj, SEL _cmd, ptrdiff_t offset, BOOL isAtomic) return ret; } +PUBLIC void objc_setProperty(id obj, SEL _cmd, ptrdiff_t offset, id arg, BOOL isAtomic, BOOL isCopy) { if (nil == obj) { return; } @@ -85,6 +87,7 @@ void objc_setProperty(id obj, SEL _cmd, ptrdiff_t offset, id arg, BOOL isAtomic, objc_release(old); } +PUBLIC void objc_setProperty_atomic(id obj, SEL _cmd, id arg, ptrdiff_t offset) { char *addr = (char*)obj; @@ -98,6 +101,7 @@ void objc_setProperty_atomic(id obj, SEL _cmd, id arg, ptrdiff_t offset) objc_release(old); } +PUBLIC void objc_setProperty_atomic_copy(id obj, SEL _cmd, id arg, ptrdiff_t offset) { char *addr = (char*)obj; @@ -112,6 +116,7 @@ void objc_setProperty_atomic_copy(id obj, SEL _cmd, id arg, ptrdiff_t offset) objc_release(old); } +PUBLIC void objc_setProperty_nonatomic(id obj, SEL _cmd, id arg, ptrdiff_t offset) { char *addr = (char*)obj; @@ -122,6 +127,7 @@ void objc_setProperty_nonatomic(id obj, SEL _cmd, id arg, ptrdiff_t offset) objc_release(old); } +PUBLIC void objc_setProperty_nonatomic_copy(id obj, SEL _cmd, id arg, ptrdiff_t offset) { char *addr = (char*)obj; @@ -131,6 +137,7 @@ void objc_setProperty_nonatomic_copy(id obj, SEL _cmd, id arg, ptrdiff_t offset) objc_release(old); } +PUBLIC void objc_copyCppObjectAtomic(void *dest, const void *src, void (*copyHelper) (void *dest, const void *source)) { @@ -143,6 +150,7 @@ void objc_copyCppObjectAtomic(void *dest, const void *src, unlock_spinlock(lock2); } +PUBLIC void objc_getCppObjectAtomic(void *dest, const void *src, void (*copyHelper) (void *dest, const void *source)) { @@ -152,6 +160,7 @@ void objc_getCppObjectAtomic(void *dest, const void *src, unlock_spinlock(lock); } +PUBLIC void objc_setCppObjectAtomic(void *dest, const void *src, void (*copyHelper) (void *dest, const void *source)) { @@ -168,6 +177,7 @@ void objc_setCppObjectAtomic(void *dest, const void *src, * pointers corresponds to the object, which causes some excessive locking to * be needed. */ +PUBLIC void objc_copyPropertyStruct(void *dest, void *src, ptrdiff_t size, @@ -194,6 +204,7 @@ void objc_copyPropertyStruct(void *dest, * Get property structure function. Copies a structure from an ivar to another * variable. Locks on the address of src. */ +PUBLIC void objc_getPropertyStruct(void *dest, void *src, ptrdiff_t size, @@ -217,6 +228,7 @@ void objc_getPropertyStruct(void *dest, * Set property structure function. Copes a structure to an ivar. Locks on * dest. */ +PUBLIC void objc_setPropertyStruct(void *dest, void *src, ptrdiff_t size, @@ -237,6 +249,7 @@ void objc_setPropertyStruct(void *dest, } +PUBLIC objc_property_t class_getProperty(Class cls, const char *name) { if (Nil == cls) @@ -259,6 +272,7 @@ objc_property_t class_getProperty(Class cls, const char *name) return NULL; } +PUBLIC objc_property_t* class_copyPropertyList(Class cls, unsigned int *outCount) { if (Nil == cls) @@ -296,7 +310,8 @@ objc_property_t* class_copyPropertyList(Class cls, unsigned int *outCount) } return list; } -static const char* property_getIVar(objc_property_t property) { +static const char* property_getIVar(objc_property_t property) +{ const char *iVar = property_getAttributes(property); if (iVar != 0) { @@ -312,6 +327,7 @@ static const char* property_getIVar(objc_property_t property) { return 0; } +PUBLIC const char *property_getName(objc_property_t property) { if (NULL == property) { return NULL; } @@ -336,6 +352,7 @@ static const char *property_getTypeEncoding(objc_property_t property) return property->type; } +PUBLIC const char *property_getAttributes(objc_property_t property) { if (NULL == property) { return NULL; } @@ -343,6 +360,7 @@ const char *property_getAttributes(objc_property_t property) } +PUBLIC objc_property_attribute_t *property_copyAttributeList(objc_property_t property, unsigned int *outCount) { @@ -533,6 +551,7 @@ PRIVATE struct objc_property propertyFromAttrs(const objc_property_attribute_t * } +PUBLIC BOOL class_addProperty(Class cls, const char *name, const objc_property_attribute_t *attributes, @@ -553,6 +572,7 @@ BOOL class_addProperty(Class cls, return YES; } +PUBLIC void class_replaceProperty(Class cls, const char *name, const objc_property_attribute_t *attributes, @@ -569,6 +589,7 @@ void class_replaceProperty(Class cls, LOCK_RUNTIME_FOR_SCOPE(); memcpy(old, &p, sizeof(struct objc_property)); } +PUBLIC char *property_copyAttributeValue(objc_property_t property, const char *attributeName) { diff --git a/unistd.h b/unistd.h index f0ce70d..1f3296d 100644 --- a/unistd.h +++ b/unistd.h @@ -4,5 +4,7 @@ # include_next "unistd.h" # define __block __attribute__((__blocks__(byref))) #else -# include_next "unistd.h" +# if __has_include_next("unitstd.h") +# include_next "unistd.h" +# endif #endif diff --git a/visibility.h b/visibility.h index d98d052..ed37593 100644 --- a/visibility.h +++ b/visibility.h @@ -1,8 +1,8 @@ +#include "objc/objc-visibility.h" + #if defined _WIN32 || defined __CYGWIN__ -# define PUBLIC __attribute__((dllexport)) # define PRIVATE #else -# define PUBLIC __attribute__ ((visibility("default"))) # define PRIVATE __attribute__ ((visibility("hidden"))) #endif #ifdef NO_LEGACY