Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 45 additions & 34 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ set(libobjc_HDRS
objc/objc-arc.h
objc/objc-auto.h
objc/objc-class.h
objc/objc-exception.h
objc/objc-runtime.h
objc/objc-visibility.h
objc/objc.h
Expand All @@ -107,12 +106,6 @@ set(libobjc_CXX_SRCS
selector_table.cc
)

# Windows does not use DWARF EH, except when using the GNU ABI (MinGW)
if (WIN32 AND NOT MINGW)
list(APPEND libobjc_CXX_SRCS eh_win32_msvc.cc)
elseif (NOT MINGW)
list(APPEND libobjc_C_SRCS eh_personality.c)
endif ()

find_package(tsl-robin-map)

Expand Down Expand Up @@ -141,6 +134,7 @@ option(LEGACY_COMPAT "Enable legacy compatibility features" OFF)
option(DEBUG_ARC_COMPAT
"Log warnings for classes that don't hit ARC fast paths" OFF)
option(ENABLE_OBJCXX "Enable support for Objective-C++" ON)
option(ENABLE_EXCEPTIONS "Enable exceptions" ON)
option(TESTS "Enable building the tests")
option(EMBEDDED_BLOCKS_RUNTIME "Include an embedded blocks runtime, rather than relying on libBlocksRuntime to supply it" ON)
option(STRICT_APPLE_COMPATIBILITY "Use strict Apple compatibility, always defining BOOL as signed char" OFF)
Expand All @@ -161,6 +155,17 @@ if (EMBEDDED_BLOCKS_RUNTIME)
list(APPEND libobjc_C_SRCS block_to_imp.c)
endif()

if (ENABLE_EXCEPTIONS)
# Windows does not use DWARF EH, except when using the GNU ABI (MinGW)
if (WIN32 AND NOT MINGW)
list(APPEND libobjc_CXX_SRCS eh_win32_msvc.cc)
elseif (NOT MINGW)
list(APPEND libobjc_C_SRCS eh_personality.c)
endif ()

list(APPEND libobjc_HDRS objc/objc-exception.h)
endif()

if (OLDABI_COMPAT)
list(APPEND libobjc_C_SRCS legacy.c abi_version.c statics_loader.c)
add_definitions(-DOLDABI_COMPAT=1)
Expand Down Expand Up @@ -220,23 +225,25 @@ endif()



if (WIN32 AND NOT MINGW)
message(STATUS "Using MSVC-compatible exception model")
elseif (MINGW)
message(STATUS "Using MinGW-compatible exception model")
list(APPEND libobjc_CXX_SRCS objcxx_eh.cc objcxx_eh_mingw.cc)
else ()
set(EH_PERSONALITY_FLAGS "")
if (CMAKE_CXX_COMPILER_TARGET)
list(APPEND EH_PERSONALITY_FLAGS "${CMAKE_CXX_COMPILE_OPTIONS_TARGET}${CMAKE_CXX_COMPILER_TARGET}")
if (ENABLE_EXCEPTIONS)
if (WIN32 AND NOT MINGW)
message(STATUS "Using MSVC-compatible exception model")
elseif (MINGW)
message(STATUS "Using MinGW-compatible exception model")
list(APPEND libobjc_CXX_SRCS objcxx_eh.cc objcxx_eh_mingw.cc)
else ()
set(EH_PERSONALITY_FLAGS "")
if (CMAKE_CXX_COMPILER_TARGET)
list(APPEND EH_PERSONALITY_FLAGS "${CMAKE_CXX_COMPILE_OPTIONS_TARGET}${CMAKE_CXX_COMPILER_TARGET}")
endif ()
add_custom_command(OUTPUT eh_trampoline.S
COMMAND ${CMAKE_CXX_COMPILER} ARGS ${EH_PERSONALITY_FLAGS} -fPIC -S "${CMAKE_SOURCE_DIR}/eh_trampoline.cc" -o - -fexceptions -fno-inline | sed "s/__gxx_personality_v0/test_eh_personality/g" > "${CMAKE_BINARY_DIR}/eh_trampoline.S"
MAIN_DEPENDENCY eh_trampoline.cc)
list(APPEND libobjc_ASM_SRCS eh_trampoline.S)
list(APPEND libobjc_CXX_SRCS objcxx_eh.cc)
# Find libm for linking, as some versions of libc++ don't link against it
find_library(M_LIBRARY m)
endif ()
add_custom_command(OUTPUT eh_trampoline.S
COMMAND ${CMAKE_CXX_COMPILER} ARGS ${EH_PERSONALITY_FLAGS} -fPIC -S "${CMAKE_SOURCE_DIR}/eh_trampoline.cc" -o - -fexceptions -fno-inline | sed "s/__gxx_personality_v0/test_eh_personality/g" > "${CMAKE_BINARY_DIR}/eh_trampoline.S"
MAIN_DEPENDENCY eh_trampoline.cc)
list(APPEND libobjc_ASM_SRCS eh_trampoline.S)
list(APPEND libobjc_CXX_SRCS objcxx_eh.cc)
# Find libm for linking, as some versions of libc++ don't link against it
find_library(M_LIBRARY m)
endif ()

if (EMBEDDED_BLOCKS_RUNTIME)
Expand All @@ -256,7 +263,9 @@ else ()
endif ()

add_library(objc SHARED ${libobjc_C_SRCS} ${libobjc_ASM_SRCS} ${libobjc_OBJC_SRCS} ${libobjc_OBJCXX_SRCS} ${libobjc_ASM_OBJS})
target_compile_options(objc PRIVATE "$<$<OR:$<COMPILE_LANGUAGE:OBJC>,$<COMPILE_LANGUAGE:OBJCXX>>:-Wno-gnu-folding-constant;-Wno-deprecated-objc-isa-usage;-Wno-objc-root-class;-fobjc-runtime=gnustep-2.0>$<$<COMPILE_LANGUAGE:C>:-Xclang;-fexceptions;-Wno-gnu-folding-constant>")

#target_compile_options(objc PRIVATE "$<$<OR:$<COMPILE_LANGUAGE:OBJC>,$<COMPILE_LANGUAGE:OBJCXX>>:-Wno-gnu-folding-constant;-Wno-deprecated-objc-isa-usage;-Wno-objc-root-class;-fobjc-runtime=gnustep-2.0>$<$<COMPILE_LANGUAGE:C>:-Xclang;-fexceptions;-Wno-gnu-folding-constant>")
target_compile_options(objc PRIVATE "$<$<OR:$<COMPILE_LANGUAGE:OBJC>,$<COMPILE_LANGUAGE:OBJCXX>>:-Wno-gnu-folding-constant;-fno-exceptions;-fno-objc-exceptions;-Wno-deprecated-objc-isa-usage;-Wno-objc-root-class;-fobjc-runtime=gnustep-2.0>$<$<COMPILE_LANGUAGE:C>:-Xclang;-Wno-gnu-folding-constant>")

list(APPEND libobjc_CXX_SRCS ${libobjcxx_CXX_SRCS})
target_sources(objc PRIVATE ${libobjc_CXX_SRCS})
Expand Down Expand Up @@ -466,13 +475,15 @@ if (TESTS)
add_subdirectory(Test)
endif (TESTS)

CHECK_CXX_SOURCE_COMPILES("
#include <stdlib.h>
extern \"C\" {
__attribute__((weak))
void *__cxa_allocate_exception(size_t thrown_size) noexcept;
}
#include <exception>
int main() { return 0; }" CXA_ALLOCATE_EXCEPTION_NOEXCEPT_COMPILES)

add_compile_definitions($<IF:$<BOOL:${CXA_ALLOCATE_EXCEPTION_NOEXCEPT_COMPILES}>,CXA_ALLOCATE_EXCEPTION_SPECIFIER=noexcept,CXA_ALLOCATE_EXCEPTION_SPECIFIER>)
if (ENABLE_EXCEPTIONS)
CHECK_CXX_SOURCE_COMPILES("
#include <stdlib.h>
extern \"C\" {
__attribute__((weak))
void *__cxa_allocate_exception(size_t thrown_size) noexcept;
}
#include <exception>
int main() { return 0; }" CXA_ALLOCATE_EXCEPTION_NOEXCEPT_COMPILES)

add_compile_definitions($<IF:$<BOOL:${CXA_ALLOCATE_EXCEPTION_NOEXCEPT_COMPILES}>,CXA_ALLOCATE_EXCEPTION_SPECIFIER=noexcept,CXA_ALLOCATE_EXCEPTION_SPECIFIER>)
endif()
68 changes: 40 additions & 28 deletions Test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

# Clear the LD_LIBRARY_PATH if GNUstep set it so that we don't accidentally use
# the installed version

Expand All @@ -19,13 +18,11 @@ set(TESTS
BlockTest_arc.m
ConstantString.m
Category.m
ExceptionTest.m
FastARC.m
FastARCPool.m
FastRefCount.m
Forward.m
ManyManySelectors.m
NestedExceptions.m
PropertyAttributeTest.m
ProtocolExtendedProperties.m
PropertyIntrospectionTest.m
Expand All @@ -43,16 +40,36 @@ set(TESTS
IVarSuperclassOverlap.m
objc_msgSend.m
msgInterpose.m
NilException.m
MethodArguments.m
zeroSizedIVar.m
exchange.m
hash_table_delete.c
hash_test.c
setSuperclass.m
UnexpectedException.m
)

if (ENABLE_EXCEPTIONS)
set(ADDITIONAL_CFLAGS "-fobjc-exceptions")

list(APPEND TESTS
ExceptionTest.m
NestedExceptions.m
NilException.m
UnexpectedException.m
)

# Don't run the tests that are specific to Itanium-style exceptions on
# Windows.
if (NOT WIN32)
list(APPEND TESTS
BoxedForeignException.m
ForeignException.m
)
endif()
else()
set(ADDITIONAL_CFLAGS "-fno-objc-exceptions")
endif()

if (EMBEDDED_BLOCKS_RUNTIME)
list(APPEND TESTS BlockImpTest.m)
endif()
Expand All @@ -73,13 +90,6 @@ if (WIN32)
objc_msgSend_WoA64.mm
)
endif()
else ()
# Don't run the tests that are specific to Itanium-style exceptions on
# Windows.
list(APPEND TESTS
BoxedForeignException.m
ForeignException.m
)
endif ()

if (ENABLE_ALL_OBJC_ARC_TESTS)
Expand All @@ -102,14 +112,14 @@ remove_definitions(-D__OBJC_RUNTIME_INTERNAL__=1)
add_library(test_runtime_legacy OBJECT Test.m)
set_target_properties(test_runtime_legacy PROPERTIES
INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR};${PROJECT_BINARY_DIR}/objc/"
COMPILE_FLAGS "-Xclang -fblocks -fobjc-runtime=gnustep-1.7"
COMPILE_FLAGS "-Xclang -fblocks -fobjc-runtime=gnustep-1.7 ${ADDITIONAL_CFLAGS}"
LINKER_LANGUAGE C
)

add_library(test_runtime OBJECT Test.m)
set_target_properties(test_runtime PROPERTIES
INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR};${PROJECT_BINARY_DIR}/objc/"
COMPILE_FLAGS "-Xclang -fblocks -fobjc-runtime=gnustep-2.0"
COMPILE_FLAGS "-Xclang -fblocks -fobjc-runtime=gnustep-2.0 ${ADDITIONAL_CFLAGS}"
LINKER_LANGUAGE C
)

Expand Down Expand Up @@ -142,16 +152,16 @@ function(addtest_flags TEST_NAME FLAGS TEST_SOURCE)
endfunction(addtest_flags)

function(addtest_variants TEST TEST_SOURCE LEGACY)
addtest_flags(${TEST} "-O0 -fobjc-runtime=gnustep-2.2 -UNDEBUG -DGS_RUNTIME_V2" "${TEST_SOURCE}")
addtest_flags(${TEST} "-O0 -fobjc-runtime=gnustep-2.2 ${ADDITIONAL_CFLAGS} -UNDEBUG -DGS_RUNTIME_V2" "${TEST_SOURCE}")
target_sources(${TEST} PRIVATE $<TARGET_OBJECTS:test_runtime>)
addtest_flags("${TEST}_optimised" "-O3 -fobjc-runtime=gnustep-2.2 -UNDEBUG -DGS_RUNTIME_V2" "${TEST_SOURCE}")
addtest_flags("${TEST}_optimised" "-O3 -fobjc-runtime=gnustep-2.2 ${ADDITIONAL_CFLAGS} -UNDEBUG -DGS_RUNTIME_V2" "${TEST_SOURCE}")
target_sources("${TEST}_optimised" PRIVATE $<TARGET_OBJECTS:test_runtime>)

# -fobjc-arc is not supported on platforms using the legacy runtime
if (${LEGACY} AND ${OLDABI_COMPAT} AND NOT ${TEST} MATCHES ".*_arc")
addtest_flags("${TEST}_legacy" "-O0 -fobjc-runtime=gnustep-1.7 -UNDEBUG" "${TEST_SOURCE}")
addtest_flags("${TEST}_legacy" "-O0 -fobjc-runtime=gnustep-1.7 ${ADDITIONAL_CFLAGS} -UNDEBUG" "${TEST_SOURCE}")
target_sources("${TEST}_legacy" PRIVATE $<TARGET_OBJECTS:test_runtime_legacy>)
addtest_flags("${TEST}_legacy_optimised" "-O3 -fobjc-runtime=gnustep-1.7 -UNDEBUG" "${TEST_SOURCE}")
addtest_flags("${TEST}_legacy_optimised" "-O3 -fobjc-runtime=gnustep-1.7 ${ADDITIONAL_CFLAGS} -UNDEBUG" "${TEST_SOURCE}")
target_sources("${TEST}_legacy_optimised" PRIVATE $<TARGET_OBJECTS:test_runtime_legacy>)
endif()
endfunction(addtest_variants)
Expand All @@ -166,18 +176,20 @@ foreach(TEST_SOURCE ${NEW_TESTS})
addtest_variants(${TEST} ${TEST_SOURCE} false)
endforeach()

# Tests that are more than a single file.
addtest_variants("CXXExceptions" "CXXException.m;CXXException.cc" true)
addtest_variants("ForwardDeclareProtocolAccess" "ForwardDeclareProtocolAccess.m;ForwardDeclareProtocol.m" true)
if (ENABLE_OBJCXX)
addtest_variants(ObjCXXEHInterop "ObjCXXEHInterop.mm;ObjCXXEHInterop.m" true)
addtest_variants(ObjCXXEHInteropTwice "ObjCXXEHInteropTwice.mm" true)
if (WIN32 AND CMAKE_CXX_COMPILER_ID STREQUAL Clang)
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0.0)
if (ENABLE_EXCEPTIONS)
# Tests that are more than a single file.
addtest_variants("CXXExceptions" "CXXException.m;CXXException.cc" true)
addtest_variants("ForwardDeclareProtocolAccess" "ForwardDeclareProtocolAccess.m;ForwardDeclareProtocol.m" true)
if (ENABLE_OBJCXX)
addtest_variants(ObjCXXEHInterop "ObjCXXEHInterop.mm;ObjCXXEHInterop.m" true)
addtest_variants(ObjCXXEHInteropTwice "ObjCXXEHInteropTwice.mm" true)
if (WIN32 AND CMAKE_CXX_COMPILER_ID STREQUAL Clang)
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0.0)
addtest_variants(ObjCXXEHInterop_arc "ObjCXXEHInterop_arc.mm;ObjCXXEHInterop_arc.m" true)
endif()
else()
addtest_variants(ObjCXXEHInterop_arc "ObjCXXEHInterop_arc.mm;ObjCXXEHInterop_arc.m" true)
endif()
else()
addtest_variants(ObjCXXEHInterop_arc "ObjCXXEHInterop_arc.mm;ObjCXXEHInterop_arc.m" true)
endif()
endif()

Expand Down
9 changes: 9 additions & 0 deletions Test/RuntimeTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ - (int) manyTypes;
- (void) synchronizedCode;
+ (void) synchronizedCode;
+ (id) shared;
#if __has_feature(objc_exceptions)
- (BOOL) basicThrowAndCatchException;
#endif
@end

@interface Bar : Foo
Expand Down Expand Up @@ -117,6 +119,8 @@ + (id) shared
@synchronized(self) { }
return nil;
}

#if __has_feature(objc_exceptions)
- (void) throwException
{
@throw exceptionObj;
Expand All @@ -138,6 +142,7 @@ - (BOOL) basicThrowAndCatchException
}
return NO;
}
#endif
@end

@implementation Bar
Expand Down Expand Up @@ -282,6 +287,7 @@ void testSynchronized()
printf("testSynchronized() ran\n");
}

#if __has_feature(objc_exceptions)
void testExceptions()
{
Foo *foo = [Foo new];
Expand All @@ -290,6 +296,7 @@ void testExceptions()
printf("testExceptions() ran\n");

}
#endif

void testRegisterAlias()
{
Expand Down Expand Up @@ -336,7 +343,9 @@ int main (int argc, const char * argv[])
printf("Instance of NSObject: %p\n", class_createInstance([NSObject class], 0));

testSynchronized();
#if __has_feature(objc_exceptions)
testExceptions();
#endif
testRegisterAlias();

return exitStatus;
Expand Down
6 changes: 6 additions & 0 deletions Test/objc_msgSend.m
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@ + (void)printf: (const char*)str, ...
+ (void)initialize
{
[self printf: "Format %s %d %f%c", "string", 42, 42.0, '\n'];
#if __has_feature(objc_exceptions)
@throw self;
#endif
}
+ nothing { return 0; }
@end
Expand Down Expand Up @@ -180,6 +182,8 @@ int main(void)
__objc_msg_forward2 = forward;
__objc_msg_forward3 = forward_slot;
TestCls = objc_getClass("MsgTest");

#if __has_feature(objc_exceptions)
int exceptionThrown = 0;
@try {
objc_msgSend(TestCls, @selector(foo));
Expand All @@ -189,6 +193,8 @@ int main(void)
exceptionThrown = 1;
}
assert(exceptionThrown && "An exception was thrown");
#endif

assert((id)0x42 == objc_msgSend(TestCls, @selector(foo)));
objc_msgSend(TestCls, @selector(nothing));
objc_msgSend(TestCls, @selector(missing));
Expand Down
9 changes: 9 additions & 0 deletions associate.m
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ static void setReference(struct reference_list *list,
lock = lock_for_pointer(r);
lock_spinlock(lock);
}
#if __has_feature(objc_exceptions)
@try
{
if (OBJC_ASSOCIATION_ASSIGN != r->policy)
Expand All @@ -180,6 +181,14 @@ static void setReference(struct reference_list *list,
r->policy = policy;
r->object = obj;
}
#else
if (OBJC_ASSOCIATION_ASSIGN != r->policy)
{
objc_release(r->object);
}
r->policy = policy;
r->object = obj;
#endif // __has_feature(objc_exceptions)
if (needLock)
{
unlock_spinlock(lock);
Expand Down
Loading