From ed4eff875146824568b3c9dabbf673667692c5bd Mon Sep 17 00:00:00 2001 From: hmelder Date: Thu, 11 Apr 2024 11:47:55 +0200 Subject: [PATCH 1/9] Add objc_msgSend_stret2_np --- objc/message.h | 10 ++++++ objc_msgSend.aarch64.S | 71 ++++++++++++++++++++++++++---------------- 2 files changed, 55 insertions(+), 26 deletions(-) diff --git a/objc/message.h b/objc/message.h index d5df0c11..b493fc7d 100644 --- a/objc/message.h +++ b/objc/message.h @@ -52,8 +52,18 @@ id objc_msgSend(id self, SEL _cmd, ...); OBJC_PUBLIC #ifdef __cplusplus id objc_msgSend_stret(id self, SEL _cmd, ...); + +# if defined(_WIN32) && defined(__ARM_ARCH_ISA_A64) +id objc_msgSend_stret2_np(id self, SEL _cmd, ...); +# endif + #else void objc_msgSend_stret(id self, SEL _cmd, ...); + +# if defined(_WIN32) && defined(__ARM_ARCH_ISA_A64) +void objc_msgSend_stret2_np(id self, SEL _cmd, ...); +# endif + #endif /** * Standard message sending function. This function must be cast to the diff --git a/objc_msgSend.aarch64.S b/objc_msgSend.aarch64.S index e9e30ba3..eea92d59 100644 --- a/objc_msgSend.aarch64.S +++ b/objc_msgSend.aarch64.S @@ -33,8 +33,8 @@ # define EH_START # define EH_END -# define EH_START_AT_OFFSET .seh_proc objc_msgSend -# define EH_END_AT_OFFSET .seh_endproc objc_msgSend +# define EH_START_AT_OFFSET(x) .seh_proc x +# define EH_END_AT_OFFSET(x) .seh_endproc x # define EH_END_PROLOGUE .seh_endprologue # define EH_START_EPILOGUE .seh_startepilogue @@ -52,8 +52,8 @@ // The following directives are either not // needed or not available with CFI -# define EH_START_AT_OFFSET -# define EH_END_AT_OFFSET +# define EH_START_AT_OFFSET(x) +# define EH_END_AT_OFFSET(x) # define EH_END_PROLOGUE # define EH_START_EPILOGUE # define EH_END_EPILOGUE @@ -63,26 +63,18 @@ # define EH_NOP #endif -.globl CDECL(objc_msgSend_fpret) -TYPE_DIRECTIVE(CDECL(objc_msgSend_fpret), %function) -.globl CDECL(objc_msgSend) -TYPE_DIRECTIVE(CDECL(objc_msgSend), %function) -.globl CDECL(objc_msgSend_stret) -TYPE_DIRECTIVE(CDECL(objc_msgSend_stret), %function) -CDECL(objc_msgSend): -CDECL(objc_msgSend_fpret): -CDECL(objc_msgSend_stret): +.macro MSGSEND fnname receiver, sel EH_START - cbz x0, 4f // Skip everything if the receiver is nil + cbz \receiver, 4f // Skip everything if the receiver is nil // Jump to 6: if this is a small object - ubfx x9, x0, #0, #SMALLOBJ_BITS + ubfx x9, \receiver, #0, #SMALLOBJ_BITS cbnz x9, 6f - ldr x9, [x0] // Load class to x9 if not a small int + ldr x9, [\receiver] // Load class to x9 if not a small int 1: ldr x9, [x9, #DTABLE_OFFSET] // Dtable -> x9 - ldr w10, [x1] // selector->index -> x10 + ldr w10, [\sel] // selector->index -> x10 ldr w11, [x9, #SHIFT_OFFSET] // dtable->shift -> x11 cmp x11, #8 // If this is a small dtable, jump to the @@ -109,12 +101,12 @@ CDECL(objc_msgSend_stret): br x9 // Tail-call the method 4: // Nil receiver - mov x0, #0 - mov v0.d[0], x0 - mov v0.d[1], x0 + mov \receiver, #0 + mov v0.d[0], \receiver + mov v0.d[1], \receiver br lr 5: // Slow lookup - EH_START_AT_OFFSET + EH_START_AT_OFFSET(\fnname) // Save anything that will be clobbered by // the call. @@ -143,7 +135,7 @@ CDECL(objc_msgSend_stret): add fp, sp, 192 // Adjust frame pointer EH_ADD_FP(192) - stp x0, x8, [sp, #-16]! // it's convenient if x0 is spilled at sp + stp \receiver, x8, [sp, #-16]! // it's convenient if \receiver is spilled at sp EH_STACK_ALLOC(16) // stp performed pre-indexing by sp-16 EH_END_PROLOGUE @@ -159,10 +151,10 @@ CDECL(objc_msgSend_stret): // the address of the receiver mov x0, sp // &self, _cmd in arguments - mov x1, x1 + mov x1, \sel bl CDECL(slowMsgLookup) // This is the only place where the EH directives // have to be accurate... - mov x9, x0 // IMP -> x9 + mov x9, \receiver // IMP -> x9 EH_START_EPILOGUE ldp x0, x1, [sp, #16] // Reload spilled argument registers @@ -185,11 +177,11 @@ CDECL(objc_msgSend_stret): EH_SAVE_FP_LR(208) // Post-increment sp += ARGUMENT_SPILL_SIZE +16 - ldp x0, x8, [sp], #(ARGUMENT_SPILL_SIZE + 16) + ldp \receiver, x8, [sp], #(ARGUMENT_SPILL_SIZE + 16) EH_STACK_ALLOC((ARGUMENT_SPILL_SIZE + 16)) EH_END_EPILOGUE - EH_END_AT_OFFSET + EH_END_AT_OFFSET(\fnname) br x9 6: @@ -204,6 +196,29 @@ CDECL(objc_msgSend_stret): b 1b EH_END +.endm + +.globl CDECL(objc_msgSend_fpret) +TYPE_DIRECTIVE(CDECL(objc_msgSend_fpret), %function) +.globl CDECL(objc_msgSend) +TYPE_DIRECTIVE(CDECL(objc_msgSend), %function) +.globl CDECL(objc_msgSend_stret) +TYPE_DIRECTIVE(CDECL(objc_msgSend_stret), %function) +CDECL(objc_msgSend): +CDECL(objc_msgSend_fpret): +/* + In AAPCS, an SRet is passed in x8, not x0 like a normal pointer parameter. + On Windows, this is only the case for POD (plain old data) types. Non trivial + types with constructors and destructors are passed in x0 on sret. + + We thus need two objc_msgSend functions on Windows on ARM64 for Sret: + 1. objc_msgSend_stret for POD Sret + 2. objc_msgSend_stret2_np for non-trivial Sret (like C++ class instances) + */ +CDECL(objc_msgSend_stret): + MSGSEND objc_msgSend, x0, x1 +CDECL(objc_msgSend_stret2_np): + MSGSEND objc_msgSend_stret, x1, x2 #ifdef _WIN32 .text @@ -219,6 +234,10 @@ CDECL(objc_msgSend_stret): .scl 2; .type 32; .endef +.def objc_msgSend_stret2_np; +.scl 2; +.type 32; +.endef .section .drectve,"yn" .ascii " /EXPORT:objc_msgSend" From d87cbd5ea986accbaa81f79ca6d5053475fe5ff6 Mon Sep 17 00:00:00 2001 From: hmelder Date: Thu, 11 Apr 2024 12:56:37 +0200 Subject: [PATCH 2/9] Guard and Export objc_msgSend_stret2_np --- objc_msgSend.aarch64.S | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/objc_msgSend.aarch64.S b/objc_msgSend.aarch64.S index eea92d59..29c7c698 100644 --- a/objc_msgSend.aarch64.S +++ b/objc_msgSend.aarch64.S @@ -204,6 +204,8 @@ TYPE_DIRECTIVE(CDECL(objc_msgSend_fpret), %function) TYPE_DIRECTIVE(CDECL(objc_msgSend), %function) .globl CDECL(objc_msgSend_stret) TYPE_DIRECTIVE(CDECL(objc_msgSend_stret), %function) +.globl CDECL(objc_msgSend_stret2_np) +TYPE_DIRECTIVE(CDECL(objc_msgSend_stret2_np), %function) CDECL(objc_msgSend): CDECL(objc_msgSend_fpret): /* @@ -218,7 +220,7 @@ CDECL(objc_msgSend_fpret): CDECL(objc_msgSend_stret): MSGSEND objc_msgSend, x0, x1 CDECL(objc_msgSend_stret2_np): - MSGSEND objc_msgSend_stret, x1, x2 + MSGSEND objc_msgSend_stret2_np, x1, x2 #ifdef _WIN32 .text @@ -243,4 +245,5 @@ CDECL(objc_msgSend_stret2_np): .ascii " /EXPORT:objc_msgSend" .ascii " /EXPORT:objc_msgSend_fpret" .ascii " /EXPORT:objc_msgSend_stret" +.ascii " /EXPORT:objc_msgSend_stret2_np" #endif \ No newline at end of file From 51b99f2782265979be1cc7187591119031b91a24 Mon Sep 17 00:00:00 2001 From: hmelder Date: Thu, 11 Apr 2024 23:14:21 -0700 Subject: [PATCH 3/9] Fix moving of return type --- objc_msgSend.aarch64.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/objc_msgSend.aarch64.S b/objc_msgSend.aarch64.S index 29c7c698..b3f59135 100644 --- a/objc_msgSend.aarch64.S +++ b/objc_msgSend.aarch64.S @@ -154,7 +154,7 @@ mov x1, \sel bl CDECL(slowMsgLookup) // This is the only place where the EH directives // have to be accurate... - mov x9, \receiver // IMP -> x9 + mov x9, x0 // IMP -> x9 EH_START_EPILOGUE ldp x0, x1, [sp, #16] // Reload spilled argument registers From abbcb9de7fb3fc79f52359cd408ad92fa1c6727a Mon Sep 17 00:00:00 2001 From: hmelder Date: Sat, 13 Apr 2024 10:42:55 -0700 Subject: [PATCH 4/9] Make architecture detection more resilient --- CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b3ad99d1..4571da40 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,7 +50,10 @@ try_compile( ) if(NOT COMPILE_SUCCESS) - string(REGEX MATCH "(aarch64|arm|i386|x86_64|powerpc64|powerpc|unknown)" ARCHITECTURE ${COMPILE_OUTPUT}) + string(REGEX MATCH "#error (aarch64|arm|i386|x86_64|powerpc64|powerpc|unknown)" ARCH_ERROR ${COMPILE_OUTPUT}) + if(ARCH_ERROR) + string(REGEX REPLACE "#error ([a-z0-9_]*)" "\\1" ARCHITECTURE ${ARCH_ERROR}) + endif() endif() set(ARCHITECTURE ${ARCHITECTURE} CACHE STRING "Architecture Type") From d36008cea8a3d103e2c6f61cc7035f52c62c9d79 Mon Sep 17 00:00:00 2001 From: hmelder Date: Sat, 13 Apr 2024 05:54:54 -0700 Subject: [PATCH 5/9] Remove architecture hackery in CMake --- CMake/detect_arch.c | 16 ---------------- CMakeLists.txt | 20 ++------------------ Test/CMakeLists.txt | 6 ++++++ 3 files changed, 8 insertions(+), 34 deletions(-) delete mode 100644 CMake/detect_arch.c diff --git a/CMake/detect_arch.c b/CMake/detect_arch.c deleted file mode 100644 index 03df356e..00000000 --- a/CMake/detect_arch.c +++ /dev/null @@ -1,16 +0,0 @@ -// detect_arch.c -#if defined(__aarch64__) -#error aarch64 -#elif defined(__arm__) -#error arm -#elif defined(__i386__) -#error i386 -#elif defined(__x86_64__) -#error x86_64 -#elif defined(__powerpc64__) -#error powerpc64 -#elif defined(__powerpc__) -#error powerpc -#else -#error unknown -#endif \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 4571da40..6a148058 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,23 +41,7 @@ if (MSVC) set(objc_LINK_FLAGS "/DEBUG /INCREMENTAL:NO ${objc_LINK_FLAGS}") endif() -# Get Architecture without relying on CMake -try_compile( - COMPILE_SUCCESS - ${CMAKE_BINARY_DIR} - ${CMAKE_SOURCE_DIR}/CMake/detect_arch.c - OUTPUT_VARIABLE COMPILE_OUTPUT -) - -if(NOT COMPILE_SUCCESS) - string(REGEX MATCH "#error (aarch64|arm|i386|x86_64|powerpc64|powerpc|unknown)" ARCH_ERROR ${COMPILE_OUTPUT}) - if(ARCH_ERROR) - string(REGEX REPLACE "#error ([a-z0-9_]*)" "\\1" ARCHITECTURE ${ARCH_ERROR}) - endif() -endif() - -set(ARCHITECTURE ${ARCHITECTURE} CACHE STRING "Architecture Type") -message(STATUS "Architecture: ${ARCHITECTURE}") +message(STATUS "Architecture as detected by CMake: ${CMAKE_SYSTEM_PROCESSOR}") # Build configuration add_compile_definitions(GNUSTEP __OBJC_RUNTIME_INTERNAL__=1) @@ -191,7 +175,7 @@ add_compile_options($<$:-march=i586>) # which is used in safe caching. # You must also update the guard in objc/runtime.h, when updating # this macro. -if (ARCHITECTURE STREQUAL "powerpc") +if (CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ppcle") add_definitions(-DNO_SAFE_CACHING) endif() diff --git a/Test/CMakeLists.txt b/Test/CMakeLists.txt index 7743cdc8..f2161e22 100644 --- a/Test/CMakeLists.txt +++ b/Test/CMakeLists.txt @@ -64,6 +64,12 @@ if (WIN32) set(ENABLE_ALL_OBJC_ARC_TESTS On) endif() endif() + + if (CMAKE_SYSTEM_PROCESSOR STREQUAL ARM64) + list(APPEND TESTS + objc_msgSend_WoA64.mm + ) + endif() else () # Don't run the tests that are specific to Itanium-style exceptions on # Windows. From 50c00de48047b0b299d641405df30f32f332c10d Mon Sep 17 00:00:00 2001 From: hmelder Date: Sat, 13 Apr 2024 05:55:07 -0700 Subject: [PATCH 6/9] Add objc_msgSend test for WoA64 --- Test/objc_msgSend_WoA64.mm | 148 +++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 Test/objc_msgSend_WoA64.mm diff --git a/Test/objc_msgSend_WoA64.mm b/Test/objc_msgSend_WoA64.mm new file mode 100644 index 00000000..fb6f179d --- /dev/null +++ b/Test/objc_msgSend_WoA64.mm @@ -0,0 +1,148 @@ +#include +#include +#include "../objc/runtime.h" +#include "../objc/hooks.h" + +// Pass and return for type size <= 8 bytes. +struct S1 { + int a[2]; +}; + +// Pass and return hfa <= 8 bytes +struct F1 { + float a[2]; +}; + +// Pass and return type size <= 16 bytes +struct S2 { + int a[4]; +}; + +// Pass and return for type size > 16 bytes. +struct S3 { + int a[5]; +}; + +// Pass and return aggregate (of size < 16 bytes) with non-trivial destructor. +// Sret and inreg: Returned in x0 +struct S4 { + int a[3]; + ~S4(); +}; +S4::~S4() { +} + +// Pass and return an object with a user-provided constructor (passed directly, +// returned indirectly) +struct S5 { + S5(); + int x; +}; +S5::S5() { + x = 42; +} + +Class TestCls; +#ifdef __has_attribute +#if __has_attribute(objc_root_class) +__attribute__((objc_root_class)) +#endif +#endif +@interface MsgTest { id isa; } @end +@implementation MsgTest ++ (S1) smallS1 { + assert(TestCls == self); + assert(strcmp("smallS1", sel_getName(_cmd)) == 0); + + S1 x; + x.a[0] = 0; + x.a[1] = 1; + return x; + +} ++ (F1) smallF1 { + assert(TestCls == self); + assert(strcmp("smallF1", sel_getName(_cmd)) == 0); + + F1 x; + x.a[0] = 0.2f; + x.a[1] = 0.5f; + return x; +} ++ (S2) smallS2 { + assert(TestCls == self); + assert(strcmp("smallS2", sel_getName(_cmd)) == 0); + + S2 x; + for (int i = 0; i < 4; i++) { + x.a[i] = i; + } + return x; +} ++ (S3) stretS3 { + assert(TestCls == self); + assert(strcmp("stretS3", sel_getName(_cmd)) == 0); + + S3 x; + for (int i = 0; i < 5; i++) { + x.a[i] = i; + } + return x; +} ++ (S4) stretInRegS4 { + assert(TestCls == self); + assert(strcmp("stretInRegS4", sel_getName(_cmd)) == 0); + + S4 x; + for (int i = 0; i < 3; i++) { + x.a[i] = i; + } + return x; +} ++ (S5) stretInRegS5 { + assert(TestCls == self); + assert(strcmp("stretInRegS5", sel_getName(_cmd)) == 0); + + return S5(); +} +@end + +int main(int argc, char *argv[]) { + #ifdef __GNUSTEP_MSGSEND__ + TestCls = objc_getClass("MsgTest"); + + // Returned in x0 + S1 ret = ((S1(*)(id, SEL))objc_msgSend)(TestCls, @selector(smallS1)); + assert(ret.a[0] == 0); + assert(ret.a[1] == 1); + + F1 retF1 = ((F1(*)(id, SEL))objc_msgSend)(TestCls, @selector(smallF1)); + assert(retF1.a[0] == 0.2f); + assert(retF1.a[1] == 0.5f); + + // Returned in x0 and x1 + S2 ret2 = ((S2(*)(id, SEL))objc_msgSend)(TestCls, @selector(smallS2)); + for (int i = 0; i < 4; i++) { + assert(ret2.a[i] == i); + } + + // Indirect result register x8 used + S3 ret3 = ((S3(*)(id, SEL))objc_msgSend_stret)(TestCls, @selector(stretS3)); + for (int i = 0; i < 5; i++) { + assert(ret3.a[i] == i); + } + + // Stret with inreg. Returned in x0. + S4 ret4 = ((S4(*)(id, SEL))objc_msgSend_stret2_np)(TestCls, @selector(stretInRegS4)); + for (int i = 0; i < 3; i++) { + assert(ret4.a[i] == i); + } + + // Stret with inreg. Returned in x0. + S5 ret5 = ((S5(*)(id, SEL))objc_msgSend_stret2_np)(TestCls, @selector(stretInRegS5)); + assert(ret5.x == 42); + + return 0; + #endif // __GNUSTEP_MSGSEND__ + return 77; +} From 8caaf4695fd17d2740f343873afbd9bdded4e3e8 Mon Sep 17 00:00:00 2001 From: hmelder Date: Sat, 13 Apr 2024 06:02:38 -0700 Subject: [PATCH 7/9] Wrap objc_msgSend_stret2_np in win32 ifdef --- objc_msgSend.aarch64.S | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/objc_msgSend.aarch64.S b/objc_msgSend.aarch64.S index b3f59135..d96ba721 100644 --- a/objc_msgSend.aarch64.S +++ b/objc_msgSend.aarch64.S @@ -204,10 +204,11 @@ TYPE_DIRECTIVE(CDECL(objc_msgSend_fpret), %function) TYPE_DIRECTIVE(CDECL(objc_msgSend), %function) .globl CDECL(objc_msgSend_stret) TYPE_DIRECTIVE(CDECL(objc_msgSend_stret), %function) -.globl CDECL(objc_msgSend_stret2_np) -TYPE_DIRECTIVE(CDECL(objc_msgSend_stret2_np), %function) CDECL(objc_msgSend): CDECL(objc_msgSend_fpret): +CDECL(objc_msgSend_stret): + MSGSEND objc_msgSend, x0, x1 + /* In AAPCS, an SRet is passed in x8, not x0 like a normal pointer parameter. On Windows, this is only the case for POD (plain old data) types. Non trivial @@ -217,12 +218,12 @@ CDECL(objc_msgSend_fpret): 1. objc_msgSend_stret for POD Sret 2. objc_msgSend_stret2_np for non-trivial Sret (like C++ class instances) */ -CDECL(objc_msgSend_stret): - MSGSEND objc_msgSend, x0, x1 +#ifdef _WIN32 +.globl CDECL(objc_msgSend_stret2_np) +TYPE_DIRECTIVE(CDECL(objc_msgSend_stret2_np), %function) CDECL(objc_msgSend_stret2_np): MSGSEND objc_msgSend_stret2_np, x1, x2 -#ifdef _WIN32 .text .def objc_msgSend; .scl 2; From 21c2ac5eccf5e59b9047a00ebe33adfa58d39d0e Mon Sep 17 00:00:00 2001 From: hmelder Date: Wed, 17 Apr 2024 14:51:05 -0700 Subject: [PATCH 8/9] Rename objc_msgSend_stret2_np to objc_msgSend_stret2 --- Test/objc_msgSend_WoA64.mm | 4 ++-- objc/message.h | 4 ++-- objc_msgSend.aarch64.S | 14 +++++++------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Test/objc_msgSend_WoA64.mm b/Test/objc_msgSend_WoA64.mm index fb6f179d..b2f42efd 100644 --- a/Test/objc_msgSend_WoA64.mm +++ b/Test/objc_msgSend_WoA64.mm @@ -133,13 +133,13 @@ int main(int argc, char *argv[]) { } // Stret with inreg. Returned in x0. - S4 ret4 = ((S4(*)(id, SEL))objc_msgSend_stret2_np)(TestCls, @selector(stretInRegS4)); + S4 ret4 = ((S4(*)(id, SEL))objc_msgSend_stret2)(TestCls, @selector(stretInRegS4)); for (int i = 0; i < 3; i++) { assert(ret4.a[i] == i); } // Stret with inreg. Returned in x0. - S5 ret5 = ((S5(*)(id, SEL))objc_msgSend_stret2_np)(TestCls, @selector(stretInRegS5)); + S5 ret5 = ((S5(*)(id, SEL))objc_msgSend_stret2)(TestCls, @selector(stretInRegS5)); assert(ret5.x == 42); return 0; diff --git a/objc/message.h b/objc/message.h index b493fc7d..f84c9d82 100644 --- a/objc/message.h +++ b/objc/message.h @@ -54,14 +54,14 @@ OBJC_PUBLIC id objc_msgSend_stret(id self, SEL _cmd, ...); # if defined(_WIN32) && defined(__ARM_ARCH_ISA_A64) -id objc_msgSend_stret2_np(id self, SEL _cmd, ...); +id objc_msgSend_stret2(id self, SEL _cmd, ...); # endif #else void objc_msgSend_stret(id self, SEL _cmd, ...); # if defined(_WIN32) && defined(__ARM_ARCH_ISA_A64) -void objc_msgSend_stret2_np(id self, SEL _cmd, ...); +void objc_msgSend_stret2(id self, SEL _cmd, ...); # endif #endif diff --git a/objc_msgSend.aarch64.S b/objc_msgSend.aarch64.S index d96ba721..a41cba56 100644 --- a/objc_msgSend.aarch64.S +++ b/objc_msgSend.aarch64.S @@ -216,13 +216,13 @@ CDECL(objc_msgSend_stret): We thus need two objc_msgSend functions on Windows on ARM64 for Sret: 1. objc_msgSend_stret for POD Sret - 2. objc_msgSend_stret2_np for non-trivial Sret (like C++ class instances) + 2. objc_msgSend_stret2 for non-trivial Sret (like C++ class instances) */ #ifdef _WIN32 -.globl CDECL(objc_msgSend_stret2_np) -TYPE_DIRECTIVE(CDECL(objc_msgSend_stret2_np), %function) -CDECL(objc_msgSend_stret2_np): - MSGSEND objc_msgSend_stret2_np, x1, x2 +.globl CDECL(objc_msgSend_stret2) +TYPE_DIRECTIVE(CDECL(objc_msgSend_stret2), %function) +CDECL(objc_msgSend_stret2): + MSGSEND objc_msgSend_stret2, x1, x2 .text .def objc_msgSend; @@ -237,7 +237,7 @@ CDECL(objc_msgSend_stret2_np): .scl 2; .type 32; .endef -.def objc_msgSend_stret2_np; +.def objc_msgSend_stret2; .scl 2; .type 32; .endef @@ -246,5 +246,5 @@ CDECL(objc_msgSend_stret2_np): .ascii " /EXPORT:objc_msgSend" .ascii " /EXPORT:objc_msgSend_fpret" .ascii " /EXPORT:objc_msgSend_stret" -.ascii " /EXPORT:objc_msgSend_stret2_np" +.ascii " /EXPORT:objc_msgSend_stret2" #endif \ No newline at end of file From 0a0ae5291475e79b965943b016b6094202d82074 Mon Sep 17 00:00:00 2001 From: hmelder Date: Fri, 26 Apr 2024 08:14:30 +0200 Subject: [PATCH 9/9] Add doc comment for objc_msgSend_stret2 --- objc/message.h | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/objc/message.h b/objc/message.h index f84c9d82..ee4fba1d 100644 --- a/objc/message.h +++ b/objc/message.h @@ -52,18 +52,38 @@ id objc_msgSend(id self, SEL _cmd, ...); OBJC_PUBLIC #ifdef __cplusplus id objc_msgSend_stret(id self, SEL _cmd, ...); - -# if defined(_WIN32) && defined(__ARM_ARCH_ISA_A64) -id objc_msgSend_stret2(id self, SEL _cmd, ...); -# endif - #else void objc_msgSend_stret(id self, SEL _cmd, ...); +#endif -# if defined(_WIN32) && defined(__ARM_ARCH_ISA_A64) +/** + * Standard message sending function. This function must be cast to the + * correct types for the function before use. The first argument is the + * receiver and the second the selector. + * + * Note that this function is only available on Windows ARM64. For a more + * portable solution to sending arbitrary messages, consider using + * objc_msg_lookup_sender() and then calling the returned IMP directly. + * + * This version of the function is used on Windows ARM64 for all messages + * that return a non-trivial data types (e.g C++ classes or structures with + * user-defined constructors) that is not returned in registers. + * Be aware that calling conventions differ between operating systems even + * within the same architecture, so take great care if using this function for + * small (two integer) structures. + * + * Why does objc_msgSend_stret2 exist? + * In AAPCS, an SRet is passed in x8, not x0 like a normal pointer parameter. + * On Windows, this is only the case for POD (plain old data) types. Non trivial + * types with constructors and destructors are passed in x0 on sret. + */ +OBJC_PUBLIC +#if defined(_WIN32) && defined(__ARM_ARCH_ISA_A64) +# ifdef __cplusplus +id objc_msgSend_stret2(id self, SEL _cmd, ...); +# else void objc_msgSend_stret2(id self, SEL _cmd, ...); # endif - #endif /** * Standard message sending function. This function must be cast to the