Skip to content

Update function type mangling to use Clang type when applicable. #34057

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

varungandhi-apple
Copy link
Contributor

@varungandhi-apple varungandhi-apple commented Sep 24, 2020

Marking as a draft as there are a bunch of TODOs.

  • Check SDKs for potential changes
  • Remove a bunch of silly whitespace changes
  • Add more tests
  • Updating printing to not print the cType if it is canonical.

@varungandhi-apple
Copy link
Contributor Author

varungandhi-apple commented Sep 24, 2020

I grepped the macOS and iOS SDKs for @convention(c) functions; there are only a handful of cases, and those shouldn't have different mangling under -use-clang-function-types. For @convention(block), there are more cases, but they are almost exclusively @convention(block) () -> () or @convention(block) (Bool) -> (), so they shouldn't be affected either.

@rjmccall
Copy link
Contributor

Bool could be affected because I assume that our canonical back-mapping for Bool is the C _Bool type, not ObjC's BOOL. Of course, that only affects non-ARM64 targets.

Copy link
Contributor

@rjmccall rjmccall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's interesting to me that you decided that it was important to set this correctly up-front rather than determine it retroactively. Can you talk about what went into that decision?

@varungandhi-apple
Copy link
Contributor Author

It's interesting to me that you decided that it was important to set this correctly up-front rather than determine it retroactively.

Are you asking about the isCanonical bit? It needs to be set to 0/1 when we create SILFunctionType values. Since SILFunctionType values are always canonical, and "undetermined" state would not be canonical, we would need to determine the bit at the moment of creating the SILFunctionType or earlier. There's a similar "problem" when we compute canonical FunctionType values for checking type equality. Given those constraints, I thought it would be easier to do it immediately when the ClangTypeInfo was being created. As a side-effect, it also makes debugging potential issues somewhat easier.

@varungandhi-apple
Copy link
Contributor Author

varungandhi-apple commented Sep 24, 2020

Bool could be affected because I assume that our canonical back-mapping for Bool is the C _Bool type, not ObjC's BOOL. Of course, that only affects non-ARM64 targets.

You're right, it's being mapped to CBool. There's only 1 place which is using this in the macOS SDK: RealityKit's swiftinterface. 🤦🏼

final public class __AssetLoadRequest {
  // other stuff
  public typealias CompletionHandler = @convention(block) (Swift.Bool) -> Swift.Void
  final public func setCompletionHandler(_ handler: @escaping RealityKit.__AssetLoadRequest.CompletionHandler)
}

I think this is not going to be a problem though, since the class is not an @objc class, it is a Swift class. So when the swiftinterface is regenerated with -use-clang-function-types, it will either have cType: "void (^)(_Bool)" or nothing (since it's canonical, we technically don't need to emit it in the swiftinterface).

@rjmccall
Copy link
Contributor

It's interesting to me that you decided that it was important to set this correctly up-front rather than determine it retroactively.

Are you asking about the isCanonical bit? It needs to be set to 0/1 when we create SILFunctionType values.

I was talking about the "derivable from Swift type" bit, which I'm guessing this PR used to call "isCanonical". (Thank you for renaming it; that would have been a very confusing name.) I don't understand why we would need to know this immediately when we create SILFunctionType values. The vast majority of SILFunctionTypes are never mangled, which is the only thing the bit affects.

@rjmccall
Copy link
Contributor

Bool could be affected because I assume that our canonical back-mapping for Bool is the C _Bool type, not ObjC's BOOL. Of course, that only affects non-ARM64 targets.

You're right, it's being mapped to CBool. There's only 1 place which is using this in the macOS SDK: RealityKit's swiftinterface. 🤦🏼

final public class __AssetLoadRequest {
  // other stuff
  public typealias CompletionHandler = @convention(block) (Swift.Bool) -> Swift.Void
  final public func setCompletionHandler(_ handler: @escaping RealityKit.__AssetLoadRequest.CompletionHandler)
}

I think this is not going to be a problem though, since the class is not an @objc class, it is a Swift class. So when the swiftinterface is regenerated with -use-clang-function-types, it will either have cType: "void (^)(_Bool)" or nothing (since it's canonical, we technically don't need to emit it in the swiftinterface).

Just to be sure, can you check what type we actually use as the SILFunctionType for this? SIL type lowering for @convention(block) function types bridges the function's component types, so it's possible that this actually bridges to use ObjCBool despite being spelled Bool. I don't remember all the details there.

The key question for SDK binary compatibility is: what native interfaces use @convention(c) or @convention(block) types? Note that we have to consider uses of imported typealiases in those native Swift interfaces, but we don't have to consider uses in non-native interfaces because the Swift mangling isn't part of the interaction.

@varungandhi-apple
Copy link
Contributor Author

Maybe I didn't express myself clearly. Here's what we need for FunctionType.

  1. We need to compare FunctionType values for equality in Sema.
    let f1 : @convention(c, cType: "fancyCType") <...> = <...>
    let f2 : @convention(c) <...> = f1
    
    This should generate a type error. Generating a type error here requires canonical type computation.
  2. If hypothetically, we had ClangTypeInfo equivalent to:
    struct ClangTypeInfoInternal {
      enum State {
        case unresolved // lazily resolved
        case derivableFromSwiftType
        case notDerivableFromSwiftType
      }
      var state : State
      var clangType : ClangType
    }
    typealias ClangTypeInfo = ClangTypeInfoInternal?
    
    We would potentially need to update the state from either unresolved -> derivableFromSwiftType or unresolved -> notDerivableFromSwiftType when computing the canonical FunctionType, because we cannot meaningfully compare two ClangTypeInfo values when either of them is in the unresolved state.

For FunctionType, the idea of lazily resolving the state (in case it is .unresolved) is still do-able because canonical type computation is an actual separate step. Today, we modify the clangType var and make sure it is canonical when computing a canonical FunctionType, so we could also have the extra dance around updating the state in the same place.

For SILFunctionType, this is not do-able because there is no separate canonical type computation step, all of them are canonical. Setting state to unresolved would break the invariant that all SILFunctionType values are canonical.

As a matter of simplicity, I chose to treat both of these uniformly by setting the state eagerly and getting rid of the unresolved case.


So this statement:

The vast majority of SILFunctionTypes are never mangled, which is the only thing the bit affects.

is mostly correct but not 100% correct. The bit also affects type equality (and as part of it, canonical type computation).

@varungandhi-apple
Copy link
Contributor Author

Talked with John separately and he mentioned that it would be better to have the "is derivable from Swift type" be a query which takes a SILFunctionType and can be used by the mangler, with the source of truth being the parameters + result + stored Clang type. The additional storage in the pointer can be used as a cache if needed, but it is no longer the source of truth.

I'm going to try out this approach, it seems simpler than what I have right now.

@varungandhi-apple varungandhi-apple force-pushed the vg-track-isDerivable-update-mangling branch from ea58b6e to 59434a6 Compare September 26, 2020 00:12
@varungandhi-apple
Copy link
Contributor Author

varungandhi-apple commented Sep 29, 2020

While writing tests, ran into a pre-existing bug with the demangler where @convention attributes are not printed in certain conditions. For example:

xcrun swift-demangle 's4main1gyySiXCvp'
$s4main1gyySiXCvp ---> main.g : (Swift.Int) -> ()

Is missing an @convention(c) which is implied by the XC. Investigating. The node structure is correct:

    kind=Type
      kind=CFunctionPointer
        kind=ArgumentTuple
          kind=Type
            kind=Structure
              kind=Module, text="Swift"
              kind=Identifier, text="Int"
        kind=ReturnType
          kind=Type
            kind=Tuple

@varungandhi-apple
Copy link
Contributor Author

Opened #34122 for the existing demangling issue.

@varungandhi-apple varungandhi-apple force-pushed the vg-track-isDerivable-update-mangling branch from 59434a6 to f804ecb Compare October 6, 2020 20:39
@varungandhi-apple varungandhi-apple force-pushed the vg-track-isDerivable-update-mangling branch from f804ecb to 5e4f8fa Compare October 7, 2020 23:51
@varungandhi-apple varungandhi-apple marked this pull request as ready for review October 7, 2020 23:51
@varungandhi-apple
Copy link
Contributor Author

@swift-ci please test Windows

@varungandhi-apple
Copy link
Contributor Author

@swift-ci please test

@varungandhi-apple varungandhi-apple changed the title Propagate 'isCanonical' bit for Clang types and use it for mangling. Update function type mangling to use Clang type when applicable. Oct 8, 2020
@zoecarver
Copy link
Contributor

@swift-ci please test windows platform.

@zoecarver
Copy link
Contributor

@swift-ci please test Windows platform.

@swift-ci
Copy link
Contributor

swift-ci commented Oct 8, 2020

Build failed
Swift Test Linux Platform
Git Sha - 5e4f8fa1d889bfc58009898cd93a988127241e50

@varungandhi-apple varungandhi-apple force-pushed the vg-track-isDerivable-update-mangling branch from 5e4f8fa to 650fadc Compare October 8, 2020 02:13
@varungandhi-apple
Copy link
Contributor Author

@swift-ci please test Windows platform

@varungandhi-apple
Copy link
Contributor Author

@swift-ci please test

@varungandhi-apple
Copy link
Contributor Author

@swift-ci please clean test Windows platform

@varungandhi-apple
Copy link
Contributor Author

@swift-ci please test Windows platform

@varungandhi-apple varungandhi-apple force-pushed the vg-track-isDerivable-update-mangling branch from 650fadc to 2aa73a1 Compare October 9, 2020 03:58
@varungandhi-apple
Copy link
Contributor Author

@swift-ci please test Windows platform

@varungandhi-apple
Copy link
Contributor Author

@swift-ci please test Windows platform

@varungandhi-apple
Copy link
Contributor Author

Now the issue is size_t expands to unsigned long long on Windows, not unsigned long, which still means that the mangling is different on Windows. Fixing that...

@varungandhi-apple varungandhi-apple force-pushed the vg-track-isDerivable-update-mangling branch from 2aa73a1 to 1c43570 Compare October 9, 2020 16:41
@varungandhi-apple
Copy link
Contributor Author

@swift-ci please test Windows

2 similar comments
@varungandhi-apple
Copy link
Contributor Author

@swift-ci please test Windows

@varungandhi-apple
Copy link
Contributor Author

@swift-ci please test Windows

@varungandhi-apple varungandhi-apple force-pushed the vg-track-isDerivable-update-mangling branch from 1c43570 to 44b017c Compare October 9, 2020 17:40
@varungandhi-apple
Copy link
Contributor Author

@swift-ci please test Windows

@varungandhi-apple
Copy link
Contributor Author

@swift-ci please test

@varungandhi-apple varungandhi-apple force-pushed the vg-track-isDerivable-update-mangling branch 2 times, most recently from ccd6d2f to e90e486 Compare October 15, 2020 21:48
@varungandhi-apple
Copy link
Contributor Author

@swift-ci please test

@varungandhi-apple
Copy link
Contributor Author

@swift-ci please test Windows

Copy link
Contributor

@rjmccall rjmccall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think all of my substantive comments are satisfied; LGTM.


// CHECK: p3c: @convention(c)
// CHECK: @convention(c, cType: "void (*)(size_t)")
p3c: @convention(c, cType: "void (*)(void (*)(size_t))") (@convention(c, cType: "void (*)(size_t)") (Int) -> Void) -> Void
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder what github is trying to tell us about these colons.

@varungandhi-apple varungandhi-apple force-pushed the vg-track-isDerivable-update-mangling branch from e90e486 to 6cb71c6 Compare October 21, 2020 22:58
@varungandhi-apple
Copy link
Contributor Author

@swift-ci smoke test and merge

@swift-ci swift-ci merged commit cb900a6 into swiftlang:main Oct 22, 2020
drodriguez added a commit to drodriguez/swift that referenced this pull request Nov 4, 2020
`size_t` differs in 32 bit platforms like Android ARMv7 where it is
`unsigned int` instead of `unsigned long`. The mangling changes one of the
characters.

The original tests are disabled in Android, and they are replicated in
different files for Android, with both the 32 and the 64 bits versions
of the mangling and the function signatures.

The original tests are not modified in order to avoid complicated checks
to avoid platforms like iphonesimulator-i386, which is a 32 bit
platform, but still uses `unsigned long` as the underlying type for
`size_t`

Both tests started failing after swiftlang#34057 landed in the Android 32 bits CI
machines.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants