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.
main
David Chisnall 8 years ago
parent f352f62423
commit 934cd13a7a

@ -1,7 +1,6 @@
cmake_minimum_required(VERSION 3.1) cmake_minimum_required(VERSION 3.1)
project(libobjc) project(libobjc C ASM CXX)
enable_language(ASM)
INCLUDE (CheckCXXSourceCompiles) INCLUDE (CheckCXXSourceCompiles)
@ -10,13 +9,15 @@ macro(install_symlink filepath sympath)
install(CODE "message(\"-- Symlinking: ${sympath} -> ${filepath}\")") install(CODE "message(\"-- Symlinking: ${sympath} -> ${filepath}\")")
endmacro(install_symlink) 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_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(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 # Build configuration
add_definitions( -DGNUSTEP -D__OBJC_RUNTIME_INTERNAL__=1) add_definitions( -DGNUSTEP -D__OBJC_RUNTIME_INTERNAL__=1)
@ -37,7 +38,6 @@ set(libobjc_C_SRCS
category_loader.c category_loader.c
class_table.c class_table.c
dtable.c dtable.c
eh_personality.c
encoding2.c encoding2.c
hooks.c hooks.c
ivar.c ivar.c
@ -68,10 +68,16 @@ set(libobjc_HDRS
objc/objc.h objc/objc.h
objc/runtime-deprecated.h objc/runtime-deprecated.h
objc/runtime.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) set(libobjcxx_CXX_SRCS objcxx_eh.cc)
endif (WIN32)
# For release builds, we disable spamming the terminal with warnings about # For release builds, we disable spamming the terminal with warnings about
# selector type mismatches # selector type mismatches
@ -154,10 +160,26 @@ endif ()
set(INSTALL_TARGETS objc) 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( set_source_files_properties(
${libobjc_OBJC_SRCS} ${libobjc_OBJC_SRCS}
PROPERTIES LANGUAGE C COMPILE_FLAGS "${CMAKE_OBJC_FLAGS} -Xclang -x -Xclang objective-c"
COMPILE_FLAGS "${CMAKE_OBJC_FLAGS}"
) )
# #
@ -186,9 +208,23 @@ set(ENABLE_OBJCXX true CACHE BOOL
set(CXXRT_IS_STDLIB false) 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) if (ENABLE_OBJCXX)
if (WIN32)
message(STATUS "Using MSVC-compatible exception model")
else ()
message(STATUS "Testing C++ interop") message(STATUS "Testing C++ interop")
# Try to find libcxxrt.so. We can link to this to provide the C++ ABI # Try to find libcxxrt.so. We can link to this to provide the C++ ABI
# layer, if it exists. # layer, if it exists.
@ -221,6 +257,7 @@ if (ENABLE_OBJCXX)
set(ENABLE_OBJCXX false) set(ENABLE_OBJCXX false)
endif() endif()
endif () endif ()
endif ()
endif (ENABLE_OBJCXX) endif (ENABLE_OBJCXX)
@ -231,8 +268,8 @@ if (ENABLE_OBJCXX)
set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "") set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "")
target_link_libraries(objc ${CXX_RUNTIME}) target_link_libraries(objc ${CXX_RUNTIME})
endif() endif()
set(libobjc_CXX_SRCS ${libobjcxx_CXX_SRCS}) list(APPEND libobjc_CXX_SRCS ${libobjcxx_CXX_SRCS})
target_sources(objc PRIVATE ${libobjcxx_CXX_SRCS}) target_sources(objc PRIVATE ${libobjc_CXX_SRCS})
endif() endif()
@ -264,8 +301,6 @@ if (BUILD_STATIC_LIBOBJC)
list(APPEND INSTALL_TARGETS objc-static) list(APPEND INSTALL_TARGETS objc-static)
endif () endif ()
# Explicitly link libgc if we are compiling with gc support. # Explicitly link libgc if we are compiling with gc support.
if (LIBGC) if (LIBGC)
target_link_libraries(objc ${LIBGC}) target_link_libraries(objc ${LIBGC})

@ -1,14 +1,14 @@
#import "objc/runtime.h" #include "objc/runtime.h"
#import "class.h" #include "class.h"
#import "loader.h" #include "loader.h"
#import "lock.h" #include "lock.h"
#import "objc/blocks_runtime.h" #include "objc/blocks_runtime.h"
#import "dtable.h" #include "dtable.h"
#include <assert.h> #include <assert.h>
struct objc_class _NSConcreteGlobalBlock; PUBLIC struct objc_class _NSConcreteGlobalBlock;
struct objc_class _NSConcreteStackBlock; PUBLIC struct objc_class _NSConcreteStackBlock;
struct objc_class _NSConcreteMallocBlock; PUBLIC struct objc_class _NSConcreteMallocBlock;
static struct objc_class _NSConcreteGlobalBlockMeta; static struct objc_class _NSConcreteGlobalBlockMeta;
static struct objc_class _NSConcreteStackBlockMeta; static struct objc_class _NSConcreteStackBlockMeta;
@ -40,6 +40,7 @@ static void createNSBlockSubclass(Class superclass, Class newClass,
#define NEW_CLASS(super, sub) \ #define NEW_CLASS(super, sub) \
createNSBlockSubclass(super, &sub, &sub ## Meta, #sub) createNSBlockSubclass(super, &sub, &sub ## Meta, #sub)
PUBLIC
BOOL objc_create_block_classes_as_subclasses_of(Class super) BOOL objc_create_block_classes_as_subclasses_of(Class super)
{ {
if (_NSBlock.super_class != NULL) { return NO; } if (_NSBlock.super_class != NULL) { return NO; }

@ -3,6 +3,16 @@
# the installed version # 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. # List of single-file tests.
set(TESTS set(TESTS
alias.m alias.m
@ -14,10 +24,8 @@ set(TESTS
BlockImpTest.m BlockImpTest.m
BlockTest_arc.m BlockTest_arc.m
ConstantString.m ConstantString.m
BoxedForeignException.m
Category.m Category.m
ExceptionTest.m ExceptionTest.m
ForeignException.m
Forward.m Forward.m
ManyManySelectors.m ManyManySelectors.m
NestedExceptions.m NestedExceptions.m
@ -43,24 +51,33 @@ set(TESTS
setSuperclass.m 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 # List of single-file tests that won't work with the legacy ABI and so
# shouldn't be run in legacy mode. # shouldn't be run in legacy mode.
set(NEW_TESTS set(NEW_TESTS
category_properties.m category_properties.m
) )
remove_definitions(-D__OBJC_RUNTIME_INTERNAL__=1)
add_library(test_runtime_legacy OBJECT Test.m) add_library(test_runtime_legacy OBJECT Test.m)
set_target_properties(test_runtime_legacy PROPERTIES set_target_properties(test_runtime_legacy PROPERTIES
INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}" 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 LINKER_LANGUAGE C
) )
add_library(test_runtime OBJECT Test.m) add_library(test_runtime OBJECT Test.m)
set_target_properties(test_runtime PROPERTIES set_target_properties(test_runtime PROPERTIES
INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}" 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 LINKER_LANGUAGE C
) )
@ -71,14 +88,14 @@ function(addtest_flags TEST_NAME FLAGS TEST_SOURCE)
if (${TEST_NAME} MATCHES ".*_arc") if (${TEST_NAME} MATCHES ".*_arc")
# Only compile the main file with ARC # Only compile the main file with ARC
set_source_files_properties(${TEST_SOURCE} set_source_files_properties(${TEST_SOURCE}
COMPILE_FLAGS "-fobjc-arc") COMPILE_FLAGS "-Xclang -fobjc-arc")
endif() endif()
add_executable(${TEST_NAME} ${TEST_SOURCE}) add_executable(${TEST_NAME} ${TEST_SOURCE})
add_test(${TEST_NAME} ${TEST_NAME}) add_test(${TEST_NAME} ${TEST_NAME})
set(ARC "") set(ARC "")
set_target_properties(${TEST_NAME} PROPERTIES set_target_properties(${TEST_NAME} PROPERTIES
INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}" INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}"
COMPILE_FLAGS "-fblocks ${FLAGS}" COMPILE_FLAGS "-Xclang -fblocks ${FLAGS}"
LINKER_LANGUAGE C LINKER_LANGUAGE C
) )
set_property(TEST ${TEST_NAME} PROPERTY set_property(TEST ${TEST_NAME} PROPERTY

@ -4,8 +4,6 @@
#include <string.h> #include <string.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
static BOOL methodCalled = NO; static BOOL methodCalled = NO;

@ -26,6 +26,7 @@ int main(void)
assert(x == e1); assert(x == e1);
@try { @try {
a = e2; a = e2;
@throw a;
} }
@catch (id y) @catch (id y)
{ {

@ -39,7 +39,7 @@ int main()
assert(strcmp(property_getAttributes(property), "Ti,VvarName") == 0); assert(strcmp(property_getAttributes(property), "Ti,VvarName") == 0);
free(properties); free(properties);
objc_property_t *clsproperties = class_copyPropertyList(object_getClass([helloclass class]), &outCount); properties = class_copyPropertyList(object_getClass([helloclass class]), &outCount);
assert(outCount == 1); assert(outCount == 1);
property = properties[0]; property = properties[0];
assert(strcmp(property_getName(property), "clsProp") == 0); assert(strcmp(property_getName(property), "clsProp") == 0);

@ -1,7 +1,11 @@
#include "Test.h" #include "Test.h"
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#ifdef _WIN32
# define sleep Sleep
#else
# include <unistd.h> # include <unistd.h>
#endif
static int exitStatus = 0; static int exitStatus = 0;
@ -125,10 +129,11 @@ id exceptionObj = @"Exception";
@catch (id e) @catch (id e)
{ {
test(e == exceptionObj); test(e == exceptionObj);
return YES;
} }
@finally @catch(...)
{ {
return YES; return NO;
} }
return NO; return NO;
} }

@ -10,7 +10,6 @@
//#define assert(x) if (!(x)) { printf("Failed %d\n", __LINE__); } //#define assert(x) if (!(x)) { printf("Failed %d\n", __LINE__); }
id objc_msgSend(id, SEL, ...);
typedef struct { int a,b,c,d,e; } s; typedef struct { int a,b,c,d,e; } s;
@interface Fake @interface Fake
@ -81,13 +80,14 @@ __attribute__((objc_root_class))
+ (void)printf: (const char*)str, ... + (void)printf: (const char*)str, ...
{ {
va_list ap; va_list ap;
char *s; char s[100];
va_start(ap, str); va_start(ap, str);
vasprintf(&s, str, ap); vsnprintf(&s, 100, str, ap);
va_end(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); assert(strcmp(s, "Format string 42 42.000000\n") ==0);
} }
+ (void)initialize + (void)initialize
@ -174,6 +174,7 @@ struct objc_slot *forward_slot(id o, SEL s)
} }
int main(void) int main(void)
{ {
__objc_msg_forward2 = forward; __objc_msg_forward2 = forward;

@ -24,4 +24,4 @@
*/ */
#include "objc/runtime.h" #include "objc/runtime.h"
Class alias_getClass(const char *alias_name); PUBLIC Class alias_getClass(const char *alias_name);

@ -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) if (NULL == alias_name)
{ {
@ -99,7 +99,7 @@ PRIVATE void alias_table_insert(Alias alias)
alias_table_internal_insert(alias_table, 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)) if ((NULL == alias) || (NULL == class))
{ {

58
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; 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 *refCount = ((uintptr_t*)obj) - 1;
uintptr_t refCountVal = __sync_fetch_and_add(refCount, 0); uintptr_t refCountVal = __sync_fetch_and_add(refCount, 0);
return (((size_t)refCountVal) & refcount_mask) + 1; 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 *refCount = ((uintptr_t*)obj) - 1;
uintptr_t refCountVal = __sync_fetch_and_add(refCount, 0); uintptr_t refCountVal = __sync_fetch_and_add(refCount, 0);
@ -292,7 +292,7 @@ static inline id retain(id obj)
return [obj retain]; 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 *refCount = ((uintptr_t*)obj) - 1;
uintptr_t refCountVal = __sync_fetch_and_add(refCount, 0); uintptr_t refCountVal = __sync_fetch_and_add(refCount, 0);
@ -330,7 +330,7 @@ BOOL objc_release_fast_no_destroy_np(id obj)
return NO; 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)) if (objc_release_fast_no_destroy_np(obj))
{ {
@ -420,7 +420,7 @@ static inline id autorelease(id obj)
return [obj autorelease]; 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(); struct arc_tls* tls = getARCThreadData();
unsigned long count = 0; unsigned long count = 0;
@ -434,7 +434,7 @@ unsigned long objc_arc_autorelease_count_np(void)
} }
return count; 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(); struct arc_tls* tls = getARCThreadData();
unsigned long count = 0; unsigned long count = 0;
@ -488,7 +488,7 @@ void *objc_autoreleasePoolPush(void)
if (0 == NewAutoreleasePool) { return NULL; } if (0 == NewAutoreleasePool) { return NULL; }
return NewAutoreleasePool(AutoreleasePool, SELECTOR(new)); return NewAutoreleasePool(AutoreleasePool, SELECTOR(new));
} }
void objc_autoreleasePoolPop(void *pool) PUBLIC void objc_autoreleasePoolPop(void *pool)
{ {
if (useARCAutoreleasePool) 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) if (nil != obj)
{ {
@ -520,7 +520,7 @@ id objc_autorelease(id obj)
return obj; return obj;
} }
id objc_autoreleaseReturnValue(id obj) PUBLIC id objc_autoreleaseReturnValue(id obj)
{ {
if (!useARCAutoreleasePool) if (!useARCAutoreleasePool)
{ {
@ -535,7 +535,7 @@ id objc_autoreleaseReturnValue(id obj)
return objc_autorelease(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() // If the previous object was released with objc_autoreleaseReturnValue()
// just before return, then it will not have actually been autoreleased. // just before return, then it will not have actually been autoreleased.
@ -567,36 +567,36 @@ id objc_retainAutoreleasedReturnValue(id obj)
return objc_retain(obj); return objc_retain(obj);
} }
id objc_retain(id obj) PUBLIC id objc_retain(id obj)
{ {
if (nil == obj) { return nil; } if (nil == obj) { return nil; }
return retain(obj); return retain(obj);
} }
id objc_retainAutorelease(id obj) PUBLIC id objc_retainAutorelease(id obj)
{ {
return objc_autorelease(objc_retain(obj)); return objc_autorelease(objc_retain(obj));
} }
id objc_retainAutoreleaseReturnValue(id obj) PUBLIC id objc_retainAutoreleaseReturnValue(id obj)
{ {
if (nil == obj) { return obj; } if (nil == obj) { return obj; }
return objc_autoreleaseReturnValue(retain(obj)); return objc_autoreleaseReturnValue(retain(obj));
} }
id objc_retainBlock(id b) PUBLIC id objc_retainBlock(id b)
{ {
return _Block_copy(b); return _Block_copy(b);
} }
void objc_release(id obj) PUBLIC void objc_release(id obj)
{ {
if (nil == obj) { return; } if (nil == obj) { return; }
release(obj); release(obj);
} }
id objc_storeStrong(id *addr, id value) PUBLIC id objc_storeStrong(id *addr, id value)
{ {
value = objc_retain(value); value = objc_retain(value);
id oldValue = *addr; id oldValue = *addr;
@ -697,7 +697,7 @@ static inline BOOL weakRefRelease(WeakRef *ref)
void* block_load_weak(void *block); 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); LOCK_FOR_SCOPE(&weakRefLock);
WeakRef *oldRef; WeakRef *oldRef;
@ -787,7 +787,7 @@ id objc_storeWeak(id *addr, id obj)
return obj; return obj;
} }
BOOL objc_delete_weak_refs(id obj) PUBLIC BOOL objc_delete_weak_refs(id obj)
{ {
LOCK_FOR_SCOPE(&weakRefLock); LOCK_FOR_SCOPE(&weakRefLock);
if (objc_test_class_flag(classForObject(obj), objc_class_flag_fast_arc)) 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 // have done so in between this thread's decrementing the reference
// count and its acquiring the lock. In this case, report failure. // count and its acquiring the lock. In this case, report failure.
uintptr_t *refCount = ((uintptr_t*)obj) - 1; 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; return NO;
} }
@ -805,13 +805,15 @@ BOOL objc_delete_weak_refs(id obj)
WeakRef *oldRef = weak_ref_table_get(weakRefs, obj); WeakRef *oldRef = weak_ref_table_get(weakRefs, obj);
if (0 != oldRef) 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 address of obj is likely to be reused, so remove it from
// the table so that we don't accidentally alias weak // the table so that we don't accidentally alias weak
// references // references
weak_ref_remove(weakRefs, obj); 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 // If the weak reference count is zero, then we should have
// already removed this. // already removed this.
assert(oldRef->weak_count > 0); assert(oldRef->weak_count > 0);
@ -819,7 +821,7 @@ BOOL objc_delete_weak_refs(id obj)
return YES; return YES;
} }
id objc_loadWeakRetained(id* addr) PUBLIC id objc_loadWeakRetained(id* addr)
{ {
LOCK_FOR_SCOPE(&weakRefLock); LOCK_FOR_SCOPE(&weakRefLock);
id obj; id obj;
@ -857,12 +859,12 @@ id objc_loadWeakRetained(id* addr)
return objc_retain(obj); return objc_retain(obj);
} }
id objc_loadWeak(id* object) PUBLIC id objc_loadWeak(id* object)
{ {
return objc_autorelease(objc_loadWeakRetained(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 // Don't retain or release. While the weak ref lock is held, we know that
// the object can't be deallocated, so we just move the value and update // the 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 // Don't retain or release. While the weak ref lock is held, we know that
// the object can't be deallocated, so we just move the value and update // the 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); objc_storeWeak(obj, nil);
} }
id objc_initWeak(id *object, id value) PUBLIC id objc_initWeak(id *object, id value)
{ {
*object = nil; *object = nil;
return objc_storeWeak(object, value); return objc_storeWeak(object, value);

@ -4,6 +4,13 @@
#define SHIFT_OFFSET 0 #define SHIFT_OFFSET 0
#define DATA_OFFSET 8 #define DATA_OFFSET 8
#define SLOT_OFFSET 0 #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 #else
#define DTABLE_OFFSET 32 #define DTABLE_OFFSET 32
#define SMALLOBJ_BITS 1 #define SMALLOBJ_BITS 1

@ -388,6 +388,7 @@ PRIVATE void gc_setTypeForClass(Class cls, void *type)
list->gc_type = type; list->gc_type = type;
} }
PUBLIC
int objc_sync_enter(id object) int objc_sync_enter(id object)
{ {
if ((object == 0) || isSmallObject(object)) { return 0; } if ((object == 0) || isSmallObject(object)) { return 0; }
@ -396,6 +397,7 @@ int objc_sync_enter(id object)
return 0; return 0;
} }
PUBLIC
int objc_sync_exit(id object) int objc_sync_exit(id object)
{ {
if ((object == 0) || isSmallObject(object)) { return 0; } if ((object == 0) || isSmallObject(object)) { return 0; }

@ -8,9 +8,11 @@
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include <ctype.h> #include <ctype.h>
#ifndef _WIN32
#include <unistd.h> #include <unistd.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/mman.h> #include <sys/mman.h>
#endif
#include "objc/runtime.h" #include "objc/runtime.h"
#include "objc/blocks_runtime.h" #include "objc/blocks_runtime.h"
#include "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) static struct trampoline_set *alloc_trampolines(char *start, char *end)
{ {
struct trampoline_set *metadata = calloc(1, sizeof(struct trampoline_set)); 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 ; i<HEADERS_PER_PAGE ; i++) for (int i=0 ; i<HEADERS_PER_PAGE ; i++)
{ {
metadata->buffers->headers[i].fnptr = (void(*)(void))invalid; metadata->buffers->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); memcpy(block, start, end-start);
} }
metadata->buffers->headers[HEADERS_PER_PAGE-1].block = NULL; 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); mprotect(metadata->buffers->rx_buffer, PAGE_SIZE, PROT_READ | PROT_EXEC);
#endif
clear_cache(metadata->buffers->rx_buffer, &metadata->buffers->rx_buffer[PAGE_SIZE]); clear_cache(metadata->buffers->rx_buffer, &metadata->buffers->rx_buffer[PAGE_SIZE]);
return metadata; return metadata;
} }

@ -42,7 +42,7 @@ static void *_HeapBlockByRef = (void*)1;
/** /**
* Returns the Objective-C type encoding for the block. * 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; const struct Block_layout *block = b;
if ((NULL == block) || !(block->flags & BLOCK_HAS_SIGNATURE)) 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 * the other choices which are mutually exclusive. Only in a Block copy helper
* will one see BLOCK_FIELD_IS_BYREF. * 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); //printf("Copying %x to %x with flags %x\n", object, destAddr, flags);
// FIXME: Needs to be implemented // 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 * The same flags used in the copy helper should be used for each call
* generated to this function: * 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 // FIXME: Needs to be implemented
//if(flags & BLOCK_FIELD_IS_WEAK) //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. // 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; } if (NULL == src) { return NULL; }
struct Block_layout *self = (struct Block_layout*)src; 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. // 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; } if (NULL == src) { return; }
struct Block_layout *self = (struct Block_layout*)src; struct Block_layout *self = (struct Block_layout*)src;

@ -34,7 +34,7 @@ static const int32_t caps =
#endif #endif
0; 0;
int objc_test_capability(int x) PUBLIC int objc_test_capability(int x)
{ {
if (x >= 32) { return 0; } if (x >= 32) { return 0; }
if (caps & (1<<x)) { return 1; } if (caps & (1<<x)) { return 1; }

@ -46,7 +46,9 @@ static inline int classHasInstalledDtable(struct objc_class *cls)
return (cls->dtable != uninstalled_dtable); return (cls->dtable != uninstalled_dtable);
} }
PUBLIC
int objc_sync_enter(id object); int objc_sync_enter(id object);
PUBLIC
int objc_sync_exit(id object); int objc_sync_exit(id object);
/** /**
* Returns the dtable for a given class. If we are currently in an +initialize * Returns the dtable for a given class. If we are currently in an +initialize

@ -6,6 +6,11 @@
#include "objc/runtime.h" #include "objc/runtime.h"
#include "visibility.h" #include "visibility.h"
#include <windows.h>
#define RtlAddGrowableFunctionTable ClangIsConfusedByTypedefReturnTypes
#include <rtlsupportapi.h>
#ifndef __has_builtin #ifndef __has_builtin
#define __has_builtin(x) 0 #define __has_builtin(x) 0
#endif #endif
@ -24,33 +29,32 @@ struct _MSVC_TypeDescriptor
struct _MSVC_CatchableType struct _MSVC_CatchableType
{ {
unsigned int flags; unsigned int flags;
_MSVC_TypeDescriptor* type; unsigned long type;
int mdisp; int mdisp;
int pdisp; int pdisp;
int vdisp; int vdisp;
int size; int size;
void* copyFunction; unsigned long copyFunction;
}; };
struct _MSVC_CatchableTypeArray struct _MSVC_CatchableTypeArray
{ {
int count; int count;
_MSVC_CatchableType* types[0]; unsigned long types[0];
}; };
struct _MSVC_ThrowInfo struct _MSVC_ThrowInfo
{ {
unsigned int attributes; unsigned int attributes;
void* pfnUnwind; unsigned long pfnUnwind;
void* pfnForwardCompat; unsigned long pfnForwardCompat;
_MSVC_CatchableTypeArray* pCatchableTypeArray; unsigned long pCatchableTypeArray;
}; };
#if defined(_WIN64) #if defined(_WIN64)
extern "C" int __ImageBase; #define IMAGE_RELATIVE(ptr, base) (static_cast<unsigned long>((ptr ? ((uintptr_t)ptr - (uintptr_t)base) : (uintptr_t)nullptr)))
#define IMAGE_RELATIVE(ptr) ((decltype(ptr))(ptr ? ((uintptr_t)ptr - (uintptr_t)&__ImageBase) : (uintptr_t)nullptr))
#else #else
#define IMAGE_RELATIVE(ptr) (ptr) #define IMAGE_RELATIVE(ptr, base) reinterpret_cast<unsigned long>((ptr))
#endif #endif
extern "C" void __stdcall _CxxThrowException(void*, _MSVC_ThrowInfo*); extern "C" void __stdcall _CxxThrowException(void*, _MSVC_ThrowInfo*);
@ -60,8 +64,11 @@ namespace
static std::string mangleObjcObject() 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@@"; return ".PAUobjc_object@@";
#endif
} }
static std::string mangleStructNamed(const char* className) static std::string mangleStructNamed(const char* className)
@ -70,13 +77,15 @@ static std::string mangleStructNamed(const char* className)
// .PAUxxx@@ = ?? struct xxx * `RTTI Type Descriptor' // .PAUxxx@@ = ?? struct xxx * `RTTI Type Descriptor'
// 64-bit: // 64-bit:
// .PEAUxxx@@ = ?? struct xxx * __ptr64 `RTTI Type Descriptor' // .PEAUxxx@@ = ?? struct xxx * __ptr64 `RTTI Type Descriptor'
return //return
auto r =
#if defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ == 8 #if defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ == 8
std::string(".PEAU") + std::string(".PEAU") +
#else #else
std::string(".PAU") + std::string(".PAU") +
#endif #endif
className + "@@"; className + "@@";
return r;
} }
void fillCatchableType(_MSVC_CatchableType* exceptType) void fillCatchableType(_MSVC_CatchableType* exceptType)
@ -86,13 +95,18 @@ void fillCatchableType(_MSVC_CatchableType* exceptType)
exceptType->pdisp = -1; exceptType->pdisp = -1;
exceptType->vdisp = 0; exceptType->vdisp = 0;
exceptType->size = sizeof(id); exceptType->size = sizeof(id);
exceptType->copyFunction = nullptr; exceptType->copyFunction = 0;
} }
} // <anonymous-namespace> } // <anonymous-namespace>
struct X {};
PUBLIC extern "C" void objc_exception_rethrow(void* exc);
PUBLIC extern "C" void objc_exception_throw(id object) 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 // This is the base vtable for all RTTI entries
static const void* typeid_vtable = *(void**)&typeid(void *); 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; size_t typeCount = 1;
// Get count of all types in exception // 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: // 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 // Add exception type and all base types to throw information
size_t curTypeIndex = 0; 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)); auto exceptType = (_MSVC_CatchableType*)_alloca(sizeof(_MSVC_CatchableType));
fillCatchableType(exceptType); fillCatchableType(exceptType);
auto mangledName = mangleStructNamed(class_getName(cls)); auto mangledName = mangleStructNamed(class_getName(cls));
CREATE_TYPE_DESCRIPTOR(exceptType->type, mangledName); _MSVC_TypeDescriptor *ty;
exceptType->type = IMAGE_RELATIVE(exceptType->type); CREATE_TYPE_DESCRIPTOR(ty, mangledName);
exceptTypes->types[curTypeIndex++] = IMAGE_RELATIVE(exceptType); exceptType->type = IMAGE_RELATIVE(ty, &x);
exceptTypes->types[curTypeIndex++] = IMAGE_RELATIVE(exceptType, &x);
} }
// Add id (struct objc_object*) // Add id (struct objc_object*)
auto exceptType = (_MSVC_CatchableType*)_alloca(sizeof(_MSVC_CatchableType)); auto exceptType = (_MSVC_CatchableType*)_alloca(sizeof(_MSVC_CatchableType));
fillCatchableType(exceptType); fillCatchableType(exceptType);
auto idName = mangleObjcObject(); auto idName = mangleObjcObject();
CREATE_TYPE_DESCRIPTOR(exceptType->type, idName); _MSVC_TypeDescriptor *ty;
exceptType->type = IMAGE_RELATIVE(exceptType->type); CREATE_TYPE_DESCRIPTOR(ty, idName);
exceptTypes->types[curTypeIndex++] = IMAGE_RELATIVE(exceptType); exceptType->type = IMAGE_RELATIVE(ty, &x);
exceptTypes->types[curTypeIndex++] = IMAGE_RELATIVE(exceptType, &x);
_MSVC_ThrowInfo ti = { _MSVC_ThrowInfo ti = {
0, // attributes 0, // attributes
NULL, // pfnUnwind 0, // pfnUnwind
NULL, // pfnForwardCompat 0, // pfnForwardCompat
IMAGE_RELATIVE(exceptTypes) // pCatchableTypeArray 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<ULONG_PTR>(&object);
exception.ExceptionInformation[2] = reinterpret_cast<ULONG_PTR>(&ti);
exception.ExceptionInformation[3] = reinterpret_cast<ULONG_PTR>(&x);
RtlRaiseException(&exception);
__builtin_unreachable(); __builtin_unreachable();
} }
PUBLIC extern "C" void objc_exception_rethrow(void* exc) PUBLIC extern "C" void objc_exception_rethrow(void* exc)
{ {
_CxxThrowException(nullptr, nullptr); _CxxThrowException(nullptr, nullptr);
__builtin_unreachable(); __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;
}

@ -8,6 +8,10 @@
#include "method.h" #include "method.h"
#include "visibility.h" #include "visibility.h"
#ifdef max
# undef max
#endif
size_t objc_alignof_type (const char *type); size_t objc_alignof_type (const char *type);
// It would be so nice if this works, but in fact it returns nonsense: // It would be so nice if this works, but in fact it returns nonsense:

@ -18,7 +18,6 @@
* which has a static size. * which has a static size.
*/ */
#include "lock.h" #include "lock.h"
#include <unistd.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>

@ -165,7 +165,10 @@ struct objc_init
struct nsstr *strings_end; struct nsstr *strings_end;
}; };
// end: objc_init // end: objc_init
#ifdef DEBUG_LOADING
#include <dlfcn.h> #include <dlfcn.h>
#endif
static enum { static enum {
LegacyABI, LegacyABI,
@ -175,7 +178,7 @@ static enum {
void registerProtocol(Protocol *proto); void registerProtocol(Protocol *proto);
void __objc_load(struct objc_init *init) PUBLIC void __objc_load(struct objc_init *init)
{ {
init_runtime(); init_runtime();
#ifdef DEBUG_LOADING #ifdef DEBUG_LOADING
@ -293,7 +296,7 @@ void __objc_load(struct objc_init *init)
} }
#ifdef OLDABI_COMPAT #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(); init_runtime();

@ -2,6 +2,7 @@
#pragma clang system_header #pragma clang system_header
#endif #endif
#include "objc-visibility.h"
#ifdef STRICT_MACOS_X #ifdef STRICT_MACOS_X
# define OBJC_NONPORTABLE __attribute__((error("Function not supported by the Apple runtime"))) # define OBJC_NONPORTABLE __attribute__((error("Function not supported by the Apple runtime")))

@ -13,9 +13,9 @@
#define BLOCKS_EXPORT extern #define BLOCKS_EXPORT extern
#endif #endif
BLOCKS_EXPORT void *_Block_copy(const void *); PUBLIC BLOCKS_EXPORT void *_Block_copy(const void *);
BLOCKS_EXPORT void _Block_release(const void *); PUBLIC BLOCKS_EXPORT void _Block_release(const void *);
BLOCKS_EXPORT const char *block_getType_np(const void *b) OBJC_NONPORTABLE; 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_copy(x) ((__typeof(x))_Block_copy((const void *)(x)))
#define Block_release(x) _Block_release((const void *)(x)) #define Block_release(x) _Block_release((const void *)(x))

@ -136,6 +136,7 @@ extern "C" {
* Run time feature test. This function returns 1 if the runtime supports the * Run time feature test. This function returns 1 if the runtime supports the
* specified feature or 0 if it does not. * specified feature or 0 if it does not.
*/ */
PUBLIC
int objc_test_capability(int x) OBJC_NONPORTABLE; int objc_test_capability(int x) OBJC_NONPORTABLE;
#ifdef __cplusplus #ifdef __cplusplus
} }

@ -1,6 +1,7 @@
#if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__) #if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__)
#pragma clang system_header #pragma clang system_header
#endif #endif
#include "objc-visibility.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -13,7 +14,7 @@ extern "C" {
#ifndef OBJC_HOOK #ifndef OBJC_HOOK
#define OBJC_HOOK extern #define OBJC_HOOK PUBLIC extern
#endif #endif
struct objc_category; 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 * 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. * 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 * New runtime forwarding hook. This is no longer used, but is retained to
* prevent errors at link time. * 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 * Forwarding hook. Takes an object and a selector and returns a method that
* handles the forwarding. * 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 * Hook defined for handling unhandled exceptions. If the unwind library
* reaches the end of the stack without finding a handler then this hook is * 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 * receiver. This should return the slot to use instead, although it may throw
* an exception or perform some other action. * 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); SEL selector, struct objc_slot2 *result);
/** /**
* Legacy hook for when selector types do not match. This is only called * 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. * 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 #ifdef __cplusplus
} }

@ -1,6 +1,7 @@
#if defined(__clang__) #if defined(__clang__)
#pragma clang system_header #pragma clang system_header
#endif #endif
#include "objc-visibility.h"
#ifndef _OBJC_MESSAGE_H_ #ifndef _OBJC_MESSAGE_H_
#define _OBJC_MESSAGE_H_ #define _OBJC_MESSAGE_H_
@ -22,6 +23,7 @@
* systems even within the same architecture, so take great care if using this * systems even within the same architecture, so take great care if using this
* function for small (two integer) structures. * function for small (two integer) structures.
*/ */
PUBLIC
id objc_msgSend(id self, SEL _cmd, ...); id objc_msgSend(id self, SEL _cmd, ...);
/** /**
* Standard message sending function. This function must be cast to the * 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 * architecture, so take great care if using this function for small (two
* integer) structures. * integer) structures.
*/ */
PUBLIC
#ifdef __cplusplus #ifdef __cplusplus
id objc_msgSend_stret(id self, SEL _cmd, ...); id objc_msgSend_stret(id self, SEL _cmd, ...);
#else #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 * This version of the function is used for all messages that return floating
* point values. * point values.
*/ */
PUBLIC
long double objc_msgSend_fpret(id self, SEL _cmd, ...); long double objc_msgSend_fpret(id self, SEL _cmd, ...);
#endif #endif

@ -1,6 +1,7 @@
#if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__) #if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__)
#pragma clang system_header #pragma clang system_header
#endif #endif
#include "objc-visibility.h"
#ifndef __OBJC_ARC_INCLUDED__ #ifndef __OBJC_ARC_INCLUDED__
#define __OBJC_ARC_INCLUDED__ #define __OBJC_ARC_INCLUDED__
@ -12,90 +13,90 @@ extern "C" {
/** /**
* Autoreleases the argument. Equivalent to [obj autorelease]. * 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 * Autoreleases a return value. This is equivalent to [obj autorelease], but
* may also store the object somewhere where it can be quickly removed without * may also store the object somewhere where it can be quickly removed without
* the need for any message sending. * 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 * Initializes object as a weak pointer and stores value in it, or nil if value
* has already begun deallocation. * 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 * Loads the object. Returns nil if the object stored at this address has
* already begun deallocation. * already begun deallocation.
*/ */
id objc_loadWeak(id* object); PUBLIC id objc_loadWeak(id* object);
/** /**
* Loads a weak value and retains it. * 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]. * 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 * Retains the argument, assuming that the argument is a normal object and has
* its reference count managed by the runtime. * its reference count managed by the runtime.
* This is intended to implement `-retain` in ARC-compatible root classes. * 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]. * 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 * Retains and releases a return value. Equivalent to
* objc_retain(objc_autoreleaseReturnValue(obj)). * 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. * Retains a return value that has previously been autoreleased and returned.
* This is equivalent to objc_retainAutoreleaseReturnValue(), but may support a * This is equivalent to objc_retainAutoreleaseReturnValue(), but may support a
* fast path, skipping the autorelease pool entirely. * fast path, skipping the autorelease pool entirely.
*/ */
id objc_retainAutoreleasedReturnValue(id obj); PUBLIC id objc_retainAutoreleasedReturnValue(id obj);
/** /**
* Retains a block. * 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 * Stores value in addr. This first retains value, then releases the old value
* at addr, and stores the retained value in the address. * 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, * Stores obj in zeroing weak pointer addr. If obj has begun deallocation,
* then this stores nil. * 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 * 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 * pool stack. Note that the returned autorelease pool is not required to be
* an object. * an object.
*/ */
void *objc_autoreleasePoolPush(void); PUBLIC void *objc_autoreleasePoolPush(void);
/** /**
* Pops the specified autorelease pool from the stack, sending release messages * Pops the specified autorelease pool from the stack, sending release messages
* to every object that has been autreleased since the pool was created. * 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 * Initializes dest as a weak pointer and stores the value stored in src into
* it. * it.
*/ */
void objc_copyWeak(id *dest, id *src); PUBLIC void objc_copyWeak(id *dest, id *src);
/** /**
* Destroys addr as a weak pointer. * 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. * 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 * 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 * 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 * This is intended to implement `-release` in ARC-compatible root
* classes. * 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 * 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 * 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 * This is intended to implement `NSDecrementExtraRefCountWasZero` for use with
* ARC-compatible classes. * 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. * 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]. * 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 * Mark the object as about to begin deallocation. All subsequent reads of
* weak pointers will return 0. This function should be called in -release, * weak pointers will return 0. This function should be called in -release,
@ -133,16 +134,16 @@ void objc_release(id obj);
* *
* Nonstandard extension. * 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. * 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 * Returns the total number of times that an object has been autoreleased in
* this thread. * 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 #ifdef __cplusplus
} }

@ -1,6 +1,7 @@
#if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__) #if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__)
#pragma clang system_header #pragma clang system_header
#endif #endif
#include "objc-visibility.h"
#ifndef __LIBOBJC_RUNTIME_H_INCLUDED__ #ifndef __LIBOBJC_RUNTIME_H_INCLUDED__
#define __LIBOBJC_RUNTIME_H_INCLUDED__ #define __LIBOBJC_RUNTIME_H_INCLUDED__
@ -124,7 +125,7 @@ typedef struct objc_method *Method;
# ifdef STRICT_APPLE_COMPATIBILITY # ifdef STRICT_APPLE_COMPATIBILITY
typedef signed char BOOL; typedef signed char BOOL;
# else # else
# ifdef __vxworks # if defined(__vxworks) || defined(_WIN32)
typedef int BOOL; typedef int BOOL;
# else # else
typedef unsigned char BOOL; typedef unsigned char BOOL;
@ -224,6 +225,7 @@ typedef struct
* registered by the runtime. The alignment must be the base-2 logarithm of * 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. * the alignment requirement and the types should be an Objective-C type encoding.
*/ */
PUBLIC
BOOL class_addIvar(Class cls, BOOL class_addIvar(Class cls,
const char *name, const char *name,
size_t size, size_t size,
@ -233,11 +235,13 @@ BOOL class_addIvar(Class cls,
/** /**
* Adds a method to the class. * Adds a method to the class.
*/ */
PUBLIC
BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types); BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types);
/** /**
* Adds a protocol to the class. * Adds a protocol to the class.
*/ */
PUBLIC
BOOL class_addProtocol(Class cls, Protocol *protocol); 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 * name are regarded as equivalent, even if they have different methods. This
* behaviour will change in a future version. * behaviour will change in a future version.
*/ */
PUBLIC
BOOL class_conformsToProtocol(Class cls, Protocol *protocol); 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 outCount argument is set to the number of instance variables returned.
* The caller is responsible for freeing the returned buffer. * The caller is responsible for freeing the returned buffer.
*/ */
PUBLIC
Ivar* class_copyIvarList(Class cls, unsigned int *outCount); 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 * outCount argument is set to the number of methods returned. The caller is
* responsible for freeing the returned buffer. * responsible for freeing the returned buffer.
*/ */
PUBLIC
Method * class_copyMethodList(Class cls, unsigned int *outCount); 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 outCount argument is set to the number of declared properties returned.
* The caller is responsible for freeing the returned buffer. * The caller is responsible for freeing the returned buffer.
*/ */
PUBLIC
objc_property_t* class_copyPropertyList(Class cls, unsigned int *outCount); 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 * outCount argument is set to the number of protocols returned. The caller is
* responsible for freeing the returned buffer. * responsible for freeing the returned buffer.
*/ */
PUBLIC
Protocol *__unsafe_unretained* class_copyProtocolList(Class cls, unsigned int *outCount); Protocol *__unsafe_unretained* class_copyProtocolList(Class cls, unsigned int *outCount);
/** /**
* Creates an instance of this class, allocating memory using malloc. * Creates an instance of this class, allocating memory using malloc.
*/ */
PUBLIC
id class_createInstance(Class cls, size_t extraBytes); 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_*() * class. This is an opaque data type and must be accessed with the method_*()
* family of functions. * family of functions.
*/ */
PUBLIC
Method class_getClassMethod(Class aClass, SEL aSelector); 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 * this class. This is an opaque data type and must be accessed with the
* ivar_*() family of functions. * ivar_*() family of functions.
*/ */
PUBLIC
Ivar class_getClassVariable(Class cls, const char* name); 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 * in this class. This is an opaque data type and must be accessed with the
* method_*() family of functions. * method_*() family of functions.
*/ */
PUBLIC
Method class_getInstanceMethod(Class aClass, SEL aSelector); 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 * class's superclasses must be loaded before this call, or the result is
* undefined with the non-fragile ABI. * undefined with the non-fragile ABI.
*/ */
PUBLIC
size_t class_getInstanceSize(Class cls); 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 * returning a pointer to the instance variable definition or a null
* pointer if no instance variable of that name was found. * pointer if no instance variable of that name was found.
*/ */
PUBLIC
Ivar class_getInstanceVariable(Class cls, const char* name); Ivar class_getInstanceVariable(Class cls, const char* name);
/** /**
* Sets the object value of a specified instance variable. * Sets the object value of a specified instance variable.
*/ */
PUBLIC
void object_setIvar(id object, Ivar ivar, id value); void object_setIvar(id object, Ivar ivar, id value);
/** /**
* Sets a named instance variable to the value specified by *value. Note that * Sets a named instance variable to the value specified by *value. Note that
* the instance variable must be a pointer-sized quantity. * the instance variable must be a pointer-sized quantity.
*/ */
PUBLIC
Ivar object_setInstanceVariable(id obj, const char *name, void *value); Ivar object_setInstanceVariable(id obj, const char *name, void *value);
/** /**
* Returns the value of the named instance variable. This should not be used * Returns the value of the named instance variable. This should not be used
* with instance variables that are not pointers. * with instance variables that are not pointers.
*/ */
PUBLIC
id object_getIvar(id object, Ivar ivar); 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. * Note that the instance variable must be a pointer-sized quantity.
*/ */
PUBLIC
Ivar object_getInstanceVariable(id obj, const char *name, void **outValue); 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 * the receiver does not have a method corresponding to this message then this
* function may return a runtime function that performs forwarding. * function may return a runtime function that performs forwarding.
*/ */
PUBLIC
IMP class_getMethodImplementation(Class cls, SEL name); IMP class_getMethodImplementation(Class cls, SEL name);
/** /**
* Identical to class_getMethodImplementation(). * Identical to class_getMethodImplementation().
*/ */
PUBLIC
IMP class_getMethodImplementation_stret(Class cls, SEL name); IMP class_getMethodImplementation_stret(Class cls, SEL name);
/** /**
* Returns the name of the class. This string is owned by the runtime and is * 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. * valid for (at least) as long as the class remains loaded.
*/ */
PUBLIC
const char * class_getName(Class cls); const char * class_getName(Class cls);
/** /**
* Retrieves metadata about the property with the specified name. * Retrieves metadata about the property with the specified name.
*/ */
PUBLIC
objc_property_t class_getProperty(Class cls, const char *name); objc_property_t class_getProperty(Class cls, const char *name);
/** /**
* Returns the superclass of the specified class. * Returns the superclass of the specified class.
*/ */
PUBLIC
Class class_getSuperclass(Class cls); Class class_getSuperclass(Class cls);
/** /**
* Returns the version of the class. Currently, the class version is not used * 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. * inside the runtime at all, however it may be used for the developer-mode ABI.
*/ */
PUBLIC
int class_getVersion(Class theClass); int class_getVersion(Class theClass);
/** /**
* Sets the version for this class. * Sets the version for this class.
*/ */
PUBLIC
void class_setVersion(Class theClass, int version); 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); const char *class_getWeakIvarLayout(Class cls);
/** /**
* Returns whether the class is a metaclass. This can be used in conjunction * Returns whether the class is a metaclass. This can be used in conjunction
* with object_getClass() for differentiating between objects and classes. * with object_getClass() for differentiating between objects and classes.
*/ */
PUBLIC
BOOL class_isMetaClass(Class cls); BOOL class_isMetaClass(Class cls);
/** /**
* Registers an alias for the class. Returns YES if the alias could be * Registers an alias for the class. Returns YES if the alias could be
* registered successfully. * registered successfully.
*/ */
OBJC_NONPORTABLE PUBLIC OBJC_NONPORTABLE
BOOL class_registerAlias_np(Class cls, const char *alias); 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 * Objective-C runtime uses typed selectors, however the types of the selector
* will be ignored and a new selector registered with the specified types. * 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); 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 * or more of the various forwarding mechanisms, then this will still return
* NO. * NO.
*/ */
PUBLIC
BOOL class_respondsToSelector(Class cls, SEL sel); BOOL class_respondsToSelector(Class cls, SEL sel);
/** /**
* Returns the instance variable layout of this class as an opaque list that * Returns the instance variable layout of this class as an opaque list that
* can be applied to other classes. * can be applied to other classes.
*/ */
PUBLIC
const char *class_getIvarLayout(Class cls); const char *class_getIvarLayout(Class cls);
/** /**
* Sets the class's instance variable layout. The layout argument must be a * Sets the class's instance variable layout. The layout argument must be a
* value returned by class_getIvarLayout(). * value returned by class_getIvarLayout().
*/ */
PUBLIC
void class_setIvarLayout(Class cls, const char *layout); 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 * because modifying the superclass of a class at run time is a very complex
* operation and this function is almost always used incorrectly. * operation and this function is almost always used incorrectly.
*/ */
__attribute__((deprecated)) PUBLIC __attribute__((deprecated))
Class class_setSuperclass(Class cls, Class newSuper); 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); void class_setWeakIvarLayout(Class cls, const char *layout);
/** /**
* Returns the name of an instance variable. * Returns the name of an instance variable.
*/ */
PUBLIC
const char* ivar_getName(Ivar ivar); const char* ivar_getName(Ivar ivar);
/** /**
* Returns the offset of an instance variable. This value can be added to the * Returns the offset of an instance variable. This value can be added to the
* object pointer to get the address of the instance variable. * object pointer to get the address of the instance variable.
*/ */
PUBLIC
ptrdiff_t ivar_getOffset(Ivar ivar); ptrdiff_t ivar_getOffset(Ivar ivar);
/** /**
* Returns the Objective-C type encoding of the instance variable. * Returns the Objective-C type encoding of the instance variable.
*/ */
PUBLIC
const char* ivar_getTypeEncoding(Ivar ivar); 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 * Objective-C method will be the self and _cmd parameters, so the returned
* value will be "@" and ":" respectively. * value will be "@" and ":" respectively.
*/ */
PUBLIC
char* method_copyArgumentType(Method method, unsigned int index); char* method_copyArgumentType(Method method, unsigned int index);
/** /**
* Copies the type encoding of an argument of this method. The caller is * Copies the type encoding of an argument of this method. The caller is
* responsible for freeing the returned C string. * responsible for freeing the returned C string.
*/ */
PUBLIC
char* method_copyReturnType(Method method); 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 * expensive on the GNUstep runtime and its use is discouraged. It is
* recommended that users call class_replaceMethod() instead. * recommended that users call class_replaceMethod() instead.
*/ */
PUBLIC
void method_exchangeImplementations(Method m1, Method m2); 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 * output string if there is enough space for the argument type and the NULL
* terminator. Its use is therefore discouraged. * terminator. Its use is therefore discouraged.
*/ */
PUBLIC
void method_getArgumentType(Method method, unsigned int index, char *dst, size_t dst_len); 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. * Returns a pointer to the function used to implement this method.
*/ */
PUBLIC
IMP method_getImplementation(Method method); 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 * although calling method_getTypeEncoding() is faster if you just require the
* types. * types.
*/ */
PUBLIC
SEL method_getName(Method method); SEL method_getName(Method method);
/** /**
* Returns the number of arguments (including self and _cmd) that this method * Returns the number of arguments (including self and _cmd) that this method
* expects. * expects.
*/ */
PUBLIC
unsigned method_getNumberOfArguments(Method method); 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 * output string if there is enough space for the argument type and the NULL
* terminator. Its use is therefore discouraged. * terminator. Its use is therefore discouraged.
*/ */
PUBLIC
void method_getReturnType(Method method, char *dst, size_t dst_len); 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 * runtime and will persist for (at least) as long as the class owning the
* method is loaded. * method is loaded.
*/ */
PUBLIC
const char * method_getTypeEncoding(Method method); 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 * expensive with the GNUstep runtime and its use is discouraged. It is
* recommended that you call class_replaceMethod() instead. * recommended that you call class_replaceMethod() instead.
*/ */
PUBLIC
IMP method_setImplementation(Method method, IMP imp); 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 * used for class variables by adding instance variables to the returned
* metaclass. * metaclass.
*/ */
PUBLIC
Class objc_allocateClassPair(Class superclass, const char *name, size_t extraBytes); 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 * attempts to send messages to instances of this class or its subclasses
* result in undefined behaviour. * result in undefined behaviour.
*/ */
PUBLIC
void objc_disposeClassPair(Class cls); 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 * loaded, it calls the _objc_lookup_class() callback to allow an external
* library to load the module providing this class. * library to load the module providing this class.
*/ */
PUBLIC
id objc_getClass(const char *name); 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. * is 0, it returns the total number of classes registered with the runtime.
* Otherwise, it copies classes and returns the number copied. * Otherwise, it copies classes and returns the number copied.
*/ */
PUBLIC
int objc_getClassList(Class *buffer, int bufferLen); int objc_getClassList(Class *buffer, int bufferLen);
/** /**
* Returns a copy of the list of all classes in the system. The caller is * 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 * responsible for freeing this list. The number of classes is returned in the
* parameter. * parameter.
*/ */
PUBLIC
Class *objc_copyClassList(unsigned int *outCount); Class *objc_copyClassList(unsigned int *outCount);
/** /**
* Returns the metaclass with the specified name. This is equivalent to * Returns the metaclass with the specified name. This is equivalent to
* calling object_getClass() on the result of objc_getClass(). * calling object_getClass() on the result of objc_getClass().
*/ */
PUBLIC
id objc_getMetaClass(const char *name); 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 * function should generally only be called early on in a program, to ensure
* that all required libraries are loaded. * that all required libraries are loaded.
*/ */
PUBLIC
id objc_getRequiredClass(const char *name); id objc_getRequiredClass(const char *name);
/** /**
* Looks up the class with the specified name, but does not invoke any * Looks up the class with the specified name, but does not invoke any
* external lazy loading mechanisms. * external lazy loading mechanisms.
*/ */
PUBLIC
id objc_lookUpClass(const char *name); id objc_lookUpClass(const char *name);
/** /**
* Returns the protocol with the specified name. * Returns the protocol with the specified name.
*/ */
PUBLIC
Protocol *objc_getProtocol(const char *name); Protocol *objc_getProtocol(const char *name);
/** /**
* Allocates a new protocol. This returns NULL if a protocol with the same * 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 * Protocols are immutable after they have been registered, so may only be
* modified between calling this function and calling objc_registerProtocol(). * modified between calling this function and calling objc_registerProtocol().
*/ */
PUBLIC
Protocol *objc_allocateProtocol(const char *name); Protocol *objc_allocateProtocol(const char *name);
/** /**
* Registers a protocol with the runtime. After this point, the protocol may * Registers a protocol with the runtime. After this point, the protocol may
* not be modified. * not be modified.
*/ */
PUBLIC
void objc_registerProtocol(Protocol *proto); void objc_registerProtocol(Protocol *proto);
/** /**
* Adds a method to the protocol. * Adds a method to the protocol.
*/ */
PUBLIC
void protocol_addMethodDescription(Protocol *aProtocol, void protocol_addMethodDescription(Protocol *aProtocol,
SEL name, SEL name,
const char *types, const char *types,
@ -604,10 +660,12 @@ void protocol_addMethodDescription(Protocol *aProtocol,
/** /**
* Adds a protocol to the protocol. * Adds a protocol to the protocol.
*/ */
PUBLIC
void protocol_addProtocol(Protocol *aProtocol, Protocol *addition); void protocol_addProtocol(Protocol *aProtocol, Protocol *addition);
/** /**
* Adds a property to the protocol. * Adds a property to the protocol.
*/ */
PUBLIC
void protocol_addProperty(Protocol *aProtocol, void protocol_addProperty(Protocol *aProtocol,
const char *name, const char *name,
const objc_property_attribute_t *attributes, 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 * adding instance variables and methods to it. A class can not have instance
* variables added to it after objc_registerClassPair() has been called. * variables added to it after objc_registerClassPair() has been called.
*/ */
PUBLIC
void objc_registerClassPair(Class cls); 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 * object. This is a pointer to the storage specified with the extraBytes
* parameter given when allocating an object. * parameter given when allocating an object.
*/ */
PUBLIC
void *object_getIndexedIvars(id obj); void *object_getIndexedIvars(id obj);
// FIXME: The GNU runtime has a version of this which omits the size parameter // 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(). * Free an object created with class_createInstance().
*/ */
PUBLIC
id object_dispose(id obj); id object_dispose(id obj);
/** /**
* Returns the class of the object. Note: the isa pointer should not be * Returns the class of the object. Note: the isa pointer should not be
* accessed directly with the GNUstep runtime. * accessed directly with the GNUstep runtime.
*/ */
PUBLIC
Class object_getClass(id obj); Class object_getClass(id obj);
/** /**
* Sets the class of the object. Note: the isa pointer should not be * Sets the class of the object. Note: the isa pointer should not be
* accessed directly with the GNUstep runtime. * accessed directly with the GNUstep runtime.
*/ */
PUBLIC
Class object_setClass(id obj, Class cls); Class object_setClass(id obj, Class cls);
/** /**
* Returns the name of the class of the object. This is equivalent to calling * Returns the name of the class of the object. This is equivalent to calling
* class_getName() on the result of object_getClass(). * class_getName() on the result of object_getClass().
*/ */
PUBLIC
const char *object_getClassName(id obj); const char *object_getClassName(id obj);
/** /**
* Returns the name of a specified property. * Returns the name of a specified property.
*/ */
PUBLIC
const char *property_getName(objc_property_t property); 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 * description of the format for this string may be found in Apple's
* Objective-C Runtime Programming Guide. * Objective-C Runtime Programming Guide.
*/ */
PUBLIC
const char *property_getAttributes(objc_property_t property); const char *property_getAttributes(objc_property_t property);
/** /**
* Returns an array of attributes for this property. * Returns an array of attributes for this property.
*/ */
PUBLIC
objc_property_attribute_t *property_copyAttributeList(objc_property_t property, objc_property_attribute_t *property_copyAttributeList(objc_property_t property,
unsigned int *outCount); 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 * that this only sets the property metadata. The property accessor methods
* must already be created. * must already be created.
*/ */
PUBLIC
BOOL class_addProperty(Class cls, BOOL class_addProperty(Class cls,
const char *name, const char *name,
const objc_property_attribute_t *attributes, 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 * Replaces property metadata. If the property does not exist, then this is
* equivalent to calling class_addProperty(). * equivalent to calling class_addProperty().
*/ */
PUBLIC
void class_replaceProperty(Class cls, void class_replaceProperty(Class cls,
const char *name, const char *name,
const objc_property_attribute_t *attributes, const objc_property_attribute_t *attributes,
@ -698,12 +767,14 @@ void class_replaceProperty(Class cls,
/** /**
* Returns a copy of a single attribute. * Returns a copy of a single attribute.
*/ */
PUBLIC
char *property_copyAttributeValue(objc_property_t property, char *property_copyAttributeValue(objc_property_t property,
const char *attributeName); const char *attributeName);
/** /**
* Testswhether a protocol conforms to another protocol. * Testswhether a protocol conforms to another protocol.
*/ */
PUBLIC
BOOL protocol_conformsToProtocol(Protocol *p, Protocol *other); 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 * the array in the variable pointed to by the last parameter. The caller is
* responsible for freeing this array. * responsible for freeing this array.
*/ */
PUBLIC
struct objc_method_description *protocol_copyMethodDescriptionList(Protocol *p, struct objc_method_description *protocol_copyMethodDescriptionList(Protocol *p,
BOOL isRequiredMethod, BOOL isInstanceMethod, unsigned int *count); 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 * stored in the variable pointed to by the last argument. The caller is
* responsible for freeing the returned array. * responsible for freeing the returned array.
*/ */
PUBLIC
objc_property_t *protocol_copyPropertyList(Protocol *p, unsigned int *count); 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 * being stored in the variable pointed to by the last argument. The caller is
* responsible for freeing the returned array. * responsible for freeing the returned array.
*/ */
PUBLIC
objc_property_t *protocol_copyPropertyList2(Protocol *p, unsigned int *count, objc_property_t *protocol_copyPropertyList2(Protocol *p, unsigned int *count,
BOOL isRequiredProperty, BOOL isInstanceProperty); 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 * number of protocols in the array being returned via the last argument. The
* caller is responsible for freeing this array. * caller is responsible for freeing this array.
*/ */
PUBLIC
Protocol *__unsafe_unretained*protocol_copyProtocolList(Protocol *p, unsigned int *count); 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. * The caller is responsible for freeing the returned array.
*/ */
PUBLIC
Protocol *__unsafe_unretained*objc_copyProtocolList(unsigned int *outCount); Protocol *__unsafe_unretained*objc_copyProtocolList(unsigned int *outCount);
/** /**
* Returns the method description for the specified method within a given * Returns the method description for the specified method within a given
* protocol. * protocol.
*/ */
PUBLIC
struct objc_method_description protocol_getMethodDescription(Protocol *p, struct objc_method_description protocol_getMethodDescription(Protocol *p,
SEL aSel, BOOL isRequiredMethod, BOOL isInstanceMethod); 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 * implementation and so its semantics may change in the future and this
* runtime may diverge from Apple's. * runtime may diverge from Apple's.
*/ */
PUBLIC
const char *_protocol_getMethodTypeEncoding(Protocol *p, SEL aSel, const char *_protocol_getMethodTypeEncoding(Protocol *p, SEL aSel,
BOOL isRequiredMethod, BOOL isInstanceMethod); BOOL isRequiredMethod, BOOL isInstanceMethod);
/** /**
* Returns the name of the specified protocol. * Returns the name of the specified protocol.
*/ */
PUBLIC
const char* protocol_getName(Protocol *p); const char* protocol_getName(Protocol *p);
/** /**
* Returns the property metadata for the property with the specified name. * Returns the property metadata for the property with the specified name.
*/ */
PUBLIC
objc_property_t protocol_getProperty(Protocol *p, const char *name, objc_property_t protocol_getProperty(Protocol *p, const char *name,
BOOL isRequiredProperty, BOOL isInstanceProperty); 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 * which made not attempt to unique protocols (or even register them with the
* runtime). * runtime).
*/ */
PUBLIC
BOOL protocol_isEqual(Protocol *p, Protocol *other); 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 * the function (either a method or a forwarding hook) that should be called in
* response to a given message. * response to a given message.
*/ */
PUBLIC
IMP objc_msg_lookup(id, SEL) OBJC_NONPORTABLE; IMP objc_msg_lookup(id, SEL) OBJC_NONPORTABLE;
/** /**
* The message lookup function used for messages sent to super in the GCC ABI. * The message lookup function used for messages sent to super in the GCC ABI.
* This specifies both the class and the * This specifies both the class and the
*/ */
PUBLIC
IMP objc_msg_lookup_super(struct objc_super*, SEL) OBJC_NONPORTABLE; IMP objc_msg_lookup_super(struct objc_super*, SEL) OBJC_NONPORTABLE;
/** /**
* Returns the name of the specified selector. * Returns the name of the specified selector.
*/ */
PUBLIC
const char *sel_getName(SEL sel); const char *sel_getName(SEL sel);
/** /**
* Registers a selector with the runtime. This is equivalent to sel_registerName(). * Registers a selector with the runtime. This is equivalent to sel_registerName().
*/ */
PUBLIC
SEL sel_getUid(const char *selName); 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 * 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. * two will return YES, but the third case will return NO.
*/ */
PUBLIC
BOOL sel_isEqual(SEL sel1, SEL sel2); BOOL sel_isEqual(SEL sel1, SEL sel2);
/** /**
* Registers an untyped selector with the runtime. * Registers an untyped selector with the runtime.
*/ */
PUBLIC
SEL sel_registerName(const char *selName); SEL sel_registerName(const char *selName);
/** /**
* Register a typed selector. * Register a typed selector.
*/ */
PUBLIC
SEL sel_registerTypedName_np(const char *selName, const char *types) OBJC_NONPORTABLE; 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 * Returns the type encoding associated with a selector, or the empty string is
* there is no such type. * there is no such type.
*/ */
PUBLIC
const char *sel_getType_np(SEL aSel) OBJC_NONPORTABLE; 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 * 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. * 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; 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 * 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. * 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; 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 * New ABI lookup function. Receiver may be modified during lookup or proxy
* forwarding and the sender may affect how lookup occurs. * forwarding and the sender may affect how lookup occurs.
*/ */
PUBLIC
extern struct objc_slot *objc_msg_lookup_sender(id *receiver, SEL selector, id sender) extern struct objc_slot *objc_msg_lookup_sender(id *receiver, SEL selector, id sender)
OBJC_NONPORTABLE OBJC_DEPRECATED; 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 * Deprecated function for accessing a slot without going via any forwarding
* mechanisms. * mechanisms.
*/ */
PUBLIC
extern struct objc_slot *objc_get_slot(Class, SEL) extern struct objc_slot *objc_get_slot(Class, SEL)
OBJC_NONPORTABLE OBJC_DEPRECATED; 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 * counter. If this value is equal to `objc_method_cache_version` then the
* slot is safe to reuse without performing another lookup. * slot is safe to reuse without performing another lookup.
*/ */
PUBLIC
extern struct objc_slot2 *objc_get_slot2(Class, SEL, uint64_t*) extern struct objc_slot2 *objc_get_slot2(Class, SEL, uint64_t*)
OBJC_NONPORTABLE; 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 * counter. If this value is equal to `objc_method_cache_version` then the
* slot is safe to reuse without performing another lookup. * slot is safe to reuse without performing another lookup.
*/ */
PUBLIC
extern struct objc_slot2 *objc_slot_lookup_version(id *receiver, SEL selector, uint64_t*) extern struct objc_slot2 *objc_slot_lookup_version(id *receiver, SEL selector, uint64_t*)
OBJC_NONPORTABLE; OBJC_NONPORTABLE;
/** /**
* Look up a slot, invoking any required forwarding mechanisms. * Look up a slot, invoking any required forwarding mechanisms.
*/ */
PUBLIC
extern IMP objc_msg_lookup2(id *receiver, SEL selector) OBJC_NONPORTABLE; 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 * 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. * argument specifies the bit pattern to use to identify the small object.
*/ */
PUBLIC
BOOL objc_registerSmallObjectClass_np(Class cls, uintptr_t classId); 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() * Returns an object previously stored by calling objc_setAssociatedObject()
* with the same arguments, or nil if none exists. * with the same arguments, or nil if none exists.
*/ */
PUBLIC
id objc_getAssociatedObject(id object, void *key); id objc_getAssociatedObject(id object, void *key);
/** /**
* Associates an object with another. This provides a mechanism for storing * 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, * 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. * 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); void objc_setAssociatedObject(id object, void *key, id value, objc_AssociationPolicy policy);
/** /**
* Removes all associations from an object. * Removes all associations from an object.
*/ */
PUBLIC
void objc_removeAssociatedObjects(id object); 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 * take an object pointer (self) as its first argument, and then the same
* arguments as the method. * arguments as the method.
*/ */
PUBLIC
IMP imp_implementationWithBlock(void *block); IMP imp_implementationWithBlock(void *block);
/** /**
* Returns the type encoding of an IMP that would be returned by passing the * 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 * block encoding for transforming to an IMP (it must take id as its first
* argument). The caller is responsible for freeing the returned value. * argument). The caller is responsible for freeing the returned value.
*/ */
PUBLIC
char *block_copyIMPTypeEncoding_np(void*block); char *block_copyIMPTypeEncoding_np(void*block);
/** /**
* Returns the block that was used in an IMP created by * Returns the block that was used in an IMP created by
* imp_implementationWithBlock(). The result of calling this function with any * imp_implementationWithBlock(). The result of calling this function with any
* other IMP is undefined. * other IMP is undefined.
*/ */
PUBLIC
void *imp_getBlock(IMP anImp); void *imp_getBlock(IMP anImp);
/** /**
* Removes a block that was converted to an IMP with * Removes a block that was converted to an IMP with
* imp_implementationWithBlock(). The result of calling this function with any * imp_implementationWithBlock(). The result of calling this function with any
* other IMP is undefined. Returns YES on success, NO on failure. * other IMP is undefined. Returns YES on success, NO on failure.
*/ */
PUBLIC
BOOL imp_removeBlock(IMP anImp); BOOL imp_removeBlock(IMP anImp);
/** /**
* Adds a method to a specific object, This method will not be added to any * Adds a method to a specific object, This method will not be added to any
* other instances of the same class. * other instances of the same class.
*/ */
PUBLIC
BOOL object_addMethod_np(id object, SEL name, IMP imp, const char *types); 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 * Replaces a method on a specific object, This method will not be added to
* any other instances of the same class. * any other instances of the same class.
*/ */
PUBLIC
IMP object_replaceMethod_np(id object, SEL name, IMP imp, const char *types); 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 * Creates a clone, in the JavaScript sense - an object which inherits both
* associated references and methods from the original object. * associated references and methods from the original object.
*/ */
PUBLIC
id object_clone_np(id object); id object_clone_np(id object);
/** /**
* Returns the prototype of the object if it was created with * Returns the prototype of the object if it was created with
* object_clone_np(), or nil otherwise. * object_clone_np(), or nil otherwise.
*/ */
PUBLIC
id object_getPrototype_np(id object); 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 * This currently sets a global value. In the future, it may be configurable
* on a per-thread basis. * on a per-thread basis.
*/ */
PUBLIC
int objc_set_apple_compatible_objcxx_exceptions(int newValue) OBJC_NONPORTABLE; int objc_set_apple_compatible_objcxx_exceptions(int newValue) OBJC_NONPORTABLE;

@ -15,4 +15,9 @@
#endif #endif
#ifdef __ELF__ #ifdef __ELF__
.section .note.GNU-stack,"",%progbits .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 #endif

@ -1,6 +1,24 @@
.macro MSGSEND receiver, sel #ifdef _WIN64
.cfi_startproc # Start emitting unwind data. We # 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 # don't actually care about any of
# the stuff except the slow call, # the stuff except the slow call,
# because that's the only one that # because that's the only one that
@ -202,26 +220,26 @@
#rdi rsi rdx #rdi rsi rdx
# We're (potentially) modifying the self argument with the lookup, so we don't want to be # We're (potentially) modifying the self argument with the lookup, so we don't want to be
.ifc "\receiver", "%rdi" .ifc "\receiver", FIRST_ARGUMENT_STR
push %rdi push FIRST_ARGUMENT
mov %rsp, %rdi mov %rsp, FIRST_ARGUMENT
push %rsi # Save _cmd (not preserved across calls) push SECOND_ARGUMENT # Save _cmd (not preserved across calls)
push %rdx push THIRD_ARGUMENT
.else .else
push %rdi # Save the sret pointer push FIRST_ARGUMENT # Save the sret pointer
push %rsi # Save self where it can be modified push SECOND_ARGUMENT # Save self where it can be modified
mov %rsp, %rdi mov %rsp, FIRST_ARGUMENT
push %rdx push THIRD_ARGUMENT
mov %rdx, %rsi # move _cmd to where the callee expects it to be mov THIRD_ARGUMENT, SECOND_ARGUMENT # move _cmd to where the callee expects it to be
.endif .endif
.cfi_adjust_cfa_offset 0xD8 FRAME_OFFSET(0xD8)
call CDECL(slowMsgLookup) # Call the slow lookup function call CDECL(slowMsgLookup) # Call the slow lookup function
mov %rax, %r10 # Load the returned IMP mov %rax, %r10 # Load the returned IMP
pop %rdx pop THIRD_ARGUMENT
pop %rsi pop SECOND_ARGUMENT
pop %rdi pop FIRST_ARGUMENT
movups 0x80(%rsp), %xmm0 movups 0x80(%rsp), %xmm0
movups 0x70(%rsp), %xmm1 movups 0x70(%rsp), %xmm1
@ -244,16 +262,43 @@
lea CDECL(SmallObjectClasses)(%rip), %r11 lea CDECL(SmallObjectClasses)(%rip), %r11
mov (%r11, %r10, 8), %r10 mov (%r11, %r10, 8), %r10
jmp 1b jmp 1b
.cfi_endproc END_PROC(\fnname)
.endm .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) .globl CDECL(objc_msgSend)
TYPE_DIRECTIVE(CDECL(objc_msgSend), @function) TYPE_DIRECTIVE(CDECL(objc_msgSend), @function)
.globl CDECL(objc_msgSend_fpret) .globl CDECL(objc_msgSend_fpret)
TYPE_DIRECTIVE(CDECL(objc_msgSend_fpret), @function) TYPE_DIRECTIVE(CDECL(objc_msgSend_fpret), @function)
CDECL(objc_msgSend_fpret): CDECL(objc_msgSend_fpret):
CDECL(objc_msgSend): CDECL(objc_msgSend):
MSGSEND %rdi, %rsi MSGSEND objc_msgSend, %rdi, %rsi
.globl CDECL(objc_msgSend_stret) .globl CDECL(objc_msgSend_stret)
TYPE_DIRECTIVE(CDECL(objc_msgSend_stret), @function) TYPE_DIRECTIVE(CDECL(objc_msgSend_stret), @function)
CDECL(objc_msgSend_stret): CDECL(objc_msgSend_stret):
MSGSEND %rsi, %rdx MSGSEND objc_msgSend_stret, %rsi, %rdx
#endif

@ -4,7 +4,7 @@
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include "unistd.h"
#include "class.h" #include "class.h"
#include "properties.h" #include "properties.h"
#include "spinlock.h" #include "spinlock.h"
@ -18,6 +18,7 @@ PRIVATE int spinlocks[spinlock_count];
/** /**
* Public function for getting a property. * Public function for getting a property.
*/ */
PUBLIC
id objc_getProperty(id obj, SEL _cmd, ptrdiff_t offset, BOOL isAtomic) id objc_getProperty(id obj, SEL _cmd, ptrdiff_t offset, BOOL isAtomic)
{ {
if (nil == obj) { return nil; } if (nil == obj) { return nil; }
@ -45,6 +46,7 @@ id objc_getProperty(id obj, SEL _cmd, ptrdiff_t offset, BOOL isAtomic)
return ret; return ret;
} }
PUBLIC
void objc_setProperty(id obj, SEL _cmd, ptrdiff_t offset, id arg, BOOL isAtomic, BOOL isCopy) void objc_setProperty(id obj, SEL _cmd, ptrdiff_t offset, id arg, BOOL isAtomic, BOOL isCopy)
{ {
if (nil == obj) { return; } 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); objc_release(old);
} }
PUBLIC
void objc_setProperty_atomic(id obj, SEL _cmd, id arg, ptrdiff_t offset) void objc_setProperty_atomic(id obj, SEL _cmd, id arg, ptrdiff_t offset)
{ {
char *addr = (char*)obj; char *addr = (char*)obj;
@ -98,6 +101,7 @@ void objc_setProperty_atomic(id obj, SEL _cmd, id arg, ptrdiff_t offset)
objc_release(old); objc_release(old);
} }
PUBLIC
void objc_setProperty_atomic_copy(id obj, SEL _cmd, id arg, ptrdiff_t offset) void objc_setProperty_atomic_copy(id obj, SEL _cmd, id arg, ptrdiff_t offset)
{ {
char *addr = (char*)obj; 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); objc_release(old);
} }
PUBLIC
void objc_setProperty_nonatomic(id obj, SEL _cmd, id arg, ptrdiff_t offset) void objc_setProperty_nonatomic(id obj, SEL _cmd, id arg, ptrdiff_t offset)
{ {
char *addr = (char*)obj; char *addr = (char*)obj;
@ -122,6 +127,7 @@ void objc_setProperty_nonatomic(id obj, SEL _cmd, id arg, ptrdiff_t offset)
objc_release(old); objc_release(old);
} }
PUBLIC
void objc_setProperty_nonatomic_copy(id obj, SEL _cmd, id arg, ptrdiff_t offset) void objc_setProperty_nonatomic_copy(id obj, SEL _cmd, id arg, ptrdiff_t offset)
{ {
char *addr = (char*)obj; 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); objc_release(old);
} }
PUBLIC
void objc_copyCppObjectAtomic(void *dest, const void *src, void objc_copyCppObjectAtomic(void *dest, const void *src,
void (*copyHelper) (void *dest, const void *source)) void (*copyHelper) (void *dest, const void *source))
{ {
@ -143,6 +150,7 @@ void objc_copyCppObjectAtomic(void *dest, const void *src,
unlock_spinlock(lock2); unlock_spinlock(lock2);
} }
PUBLIC
void objc_getCppObjectAtomic(void *dest, const void *src, void objc_getCppObjectAtomic(void *dest, const void *src,
void (*copyHelper) (void *dest, const void *source)) void (*copyHelper) (void *dest, const void *source))
{ {
@ -152,6 +160,7 @@ void objc_getCppObjectAtomic(void *dest, const void *src,
unlock_spinlock(lock); unlock_spinlock(lock);
} }
PUBLIC
void objc_setCppObjectAtomic(void *dest, const void *src, void objc_setCppObjectAtomic(void *dest, const void *src,
void (*copyHelper) (void *dest, const void *source)) 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 * pointers corresponds to the object, which causes some excessive locking to
* be needed. * be needed.
*/ */
PUBLIC
void objc_copyPropertyStruct(void *dest, void objc_copyPropertyStruct(void *dest,
void *src, void *src,
ptrdiff_t size, ptrdiff_t size,
@ -194,6 +204,7 @@ void objc_copyPropertyStruct(void *dest,
* Get property structure function. Copies a structure from an ivar to another * Get property structure function. Copies a structure from an ivar to another
* variable. Locks on the address of src. * variable. Locks on the address of src.
*/ */
PUBLIC
void objc_getPropertyStruct(void *dest, void objc_getPropertyStruct(void *dest,
void *src, void *src,
ptrdiff_t size, ptrdiff_t size,
@ -217,6 +228,7 @@ void objc_getPropertyStruct(void *dest,
* Set property structure function. Copes a structure to an ivar. Locks on * Set property structure function. Copes a structure to an ivar. Locks on
* dest. * dest.
*/ */
PUBLIC
void objc_setPropertyStruct(void *dest, void objc_setPropertyStruct(void *dest,
void *src, void *src,
ptrdiff_t size, ptrdiff_t size,
@ -237,6 +249,7 @@ void objc_setPropertyStruct(void *dest,
} }
PUBLIC
objc_property_t class_getProperty(Class cls, const char *name) objc_property_t class_getProperty(Class cls, const char *name)
{ {
if (Nil == cls) if (Nil == cls)
@ -259,6 +272,7 @@ objc_property_t class_getProperty(Class cls, const char *name)
return NULL; return NULL;
} }
PUBLIC
objc_property_t* class_copyPropertyList(Class cls, unsigned int *outCount) objc_property_t* class_copyPropertyList(Class cls, unsigned int *outCount)
{ {
if (Nil == cls) if (Nil == cls)
@ -296,7 +310,8 @@ objc_property_t* class_copyPropertyList(Class cls, unsigned int *outCount)
} }
return list; 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); const char *iVar = property_getAttributes(property);
if (iVar != 0) if (iVar != 0)
{ {
@ -312,6 +327,7 @@ static const char* property_getIVar(objc_property_t property) {
return 0; return 0;
} }
PUBLIC
const char *property_getName(objc_property_t property) const char *property_getName(objc_property_t property)
{ {
if (NULL == property) { return NULL; } if (NULL == property) { return NULL; }
@ -336,6 +352,7 @@ static const char *property_getTypeEncoding(objc_property_t property)
return property->type; return property->type;
} }
PUBLIC
const char *property_getAttributes(objc_property_t property) const char *property_getAttributes(objc_property_t property)
{ {
if (NULL == property) { return NULL; } 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, objc_property_attribute_t *property_copyAttributeList(objc_property_t property,
unsigned int *outCount) unsigned int *outCount)
{ {
@ -533,6 +551,7 @@ PRIVATE struct objc_property propertyFromAttrs(const objc_property_attribute_t *
} }
PUBLIC
BOOL class_addProperty(Class cls, BOOL class_addProperty(Class cls,
const char *name, const char *name,
const objc_property_attribute_t *attributes, const objc_property_attribute_t *attributes,
@ -553,6 +572,7 @@ BOOL class_addProperty(Class cls,
return YES; return YES;
} }
PUBLIC
void class_replaceProperty(Class cls, void class_replaceProperty(Class cls,
const char *name, const char *name,
const objc_property_attribute_t *attributes, const objc_property_attribute_t *attributes,
@ -569,6 +589,7 @@ void class_replaceProperty(Class cls,
LOCK_RUNTIME_FOR_SCOPE(); LOCK_RUNTIME_FOR_SCOPE();
memcpy(old, &p, sizeof(struct objc_property)); memcpy(old, &p, sizeof(struct objc_property));
} }
PUBLIC
char *property_copyAttributeValue(objc_property_t property, char *property_copyAttributeValue(objc_property_t property,
const char *attributeName) const char *attributeName)
{ {

@ -4,5 +4,7 @@
# include_next "unistd.h" # include_next "unistd.h"
# define __block __attribute__((__blocks__(byref))) # define __block __attribute__((__blocks__(byref)))
#else #else
# if __has_include_next("unitstd.h")
# include_next "unistd.h" # include_next "unistd.h"
# endif # endif
#endif

@ -1,8 +1,8 @@
#include "objc/objc-visibility.h"
#if defined _WIN32 || defined __CYGWIN__ #if defined _WIN32 || defined __CYGWIN__
# define PUBLIC __attribute__((dllexport))
# define PRIVATE # define PRIVATE
#else #else
# define PUBLIC __attribute__ ((visibility("default")))
# define PRIVATE __attribute__ ((visibility("hidden"))) # define PRIVATE __attribute__ ((visibility("hidden")))
#endif #endif
#ifdef NO_LEGACY #ifdef NO_LEGACY

Loading…
Cancel
Save