Calling-convention mismatch violations between runtime, stdlib, and emitted code

Hi, folks

The current Swift implementation has 4 types of calling-convention mismatch in runtime, stdlib, and code emitted by the compiler.

These violations are one of the blockers of porting to WebAssembly because swiftcc and C-cc are not compatible on WebAssembly.
In our SwiftWasm fork, we applied a hacky patch to use the same calling convention for each function. However, it may break ABI on Darwin, so I want to ask compiler folks before submitting patches to the upstream.

I'll describe the 4 issues in this post.

1. Defined as a C-cc in runtime but published as a Swift-cc public API in stdlib.

For example, swift_retainCount is declared and defined in runtime without explicit cc, so it's defined as a C-cc function. But it's published as a Swift-cc public API here in stdlib.
This means some external users can call the function assuming Swift-cc, but the actual implementation in runtime uses C-cc.

The other violating functions in the same way are:

  • swift_retainCount, swift_unownedRetainCount, swift_weakRetainCount, _swift_getObjectRuntimeFunctionCounters, _swift_getGlobalRuntimeFunctionCounters, and other RuntimeInvocationsTracking things

2. Emitted as a C-cc from user code, but called as a Swift-cc by stdlib indirectly.

For example, keypath_get_arg_layout are emitted as a C-cc function by the compiler, but it's called as a Swift-cc function in the stdlib.

Other same cases:

  • keypath_get_arg_layout, keypath_destroy, keypath_copy, keypath_arg_init

3. Defined as a C-cc in runtime, but called as a Swift-cc in stdlib

For example, _isClassType is mainly called by compiler-emitted code and defined as a C-cc function. But it's also called by stdlib.
The call-site of stdlib uses @_silgen_name to link the function, so it's called through swiftcc.
Fortunately, the API is not exposed from Swift stdlib, so no external user calls it as a Swift-cc.

4. Defined as a C-cc in runtime, but called as a Swift-cc by test binary

swift_demangle is defined as a C-cc function in runtime, but called as a Swift-cc function from test case.

How to fix them?

For case 1, we can add explicit SWIFT_CC(swift) at the definition in runtime because there is no caller that expects it to be C-cc.

For case 2, I don't know which side, runtime or compiler-generated function, should be fixed.

For case 3, the function should be called though C-cc consistently to avoid breaking ABI between generated code which expects it to be C-cc.
This case can be fixed by [stdlib] Fix cc mismatch violation on swift_isClassType by kateinoigakukun · Pull Request #39119 · apple/swift · GitHub

For case 4, this can be resolved by fixing the test case without any effect on ABI.

Do you have any idea about this issue or good solution of case 2?
And also is there any concern around ABI stability?

Ticket: [SR-15188] Calling-convention mismatch violations between runtime, stdlib, and emitted code · Issue #57511 · apple/swift · GitHub

14 Likes

@John_McCall would you have a moment to take a quick look at this? Or maybe redirect us to someone who could help with this issue? This is a major blocker for enabling WebAssembly support in upstream Swift repositories. It would be great to understand what's the best plan for moving forward with this. Thanks!

Yes, I'm sure we're playing too fast and loose with calling conventions and just getting away with it on platforms where the CCs are the same for most function signatures. It shouldn't have any effect on the ABI to fix these declarations to consistently use the Swift CC for Swift runtime functions, and we should just do that.

9 Likes

Thank you for your clarification. I was relieved to hear that it would not affect the ABI.
We will send patches to fix them.

3 Likes

Thanks for the explanation! A PR with a partial fix is ready for review: [stdlib] Fix cc mismatch violation on swift_isClassType by kateinoigakukun · Pull Request #39119 · apple/swift · GitHub

Would you have a moment to take a look?

4 Likes