swiftwasm / swift

WebAssembly support for the Swift programming language
https://swiftwasm.org
1.32k stars 28 forks source link

Mismatch in import signatures between SwiftWasm module and host function #2111

Closed cohix closed 6 months ago

cohix commented 3 years ago

I'm seeing some odd behaviour when using Wasmer (via the Go extension) to host a module built with SwiftWasm.

I have this function (exposed via CGo):

extern void print(void *context, int32_t pointer, int32_t size, int32_t ident);

With the Go signature:

func print(context unsafe.Pointer, pointer int32, size int32, identifier int32)

And I am declaring it my Swift file as:

@_silgen_name("print")
func print_msg(pointer: UnsafeRawPointer, size: Int32, ident: Int32)

However when I attempt to call this function from the Swift module, I get this error: link error: Incorrect import signature, namespace: env, name: print, expected signature: [I32, I32, I32, I32, I32] -> [], found signature: [I32, I32, I32] -> []

The Swift module seems to expect a function with 5 arguments rather than 3.

If I modify the host functions as such:

extern void print(void *context, int32_t pointer, int32_t size, int32_t ident, int32_t x, int32_t y);

And Go:

func print(context unsafe.Pointer, pointer int32, size int32, identifier int32, x int32, y int32)

Then everything works. Both of the extra params get value 0 and I can't seem to concoct a Swift function signature where this doesn't happen.

Please advise!

P.S. Otherwise things are working great! Thanks very much for the hard work!

MaxDesiatov commented 3 years ago

If your Go/C function has 4 arguments, then your Swift import should have a matching number of arguments, definitely not 3. @kateinoigakukun do you know where the 5th argument might come from? Is that swifterror? I thought we wouldn't have it in a non-throwing function...

I'm not sure if @_silgen_name is a good fit here, I recommend creating a separate C target in Package.swift that would have a C header with your function. Then you'll be able to import that module into Swift with the exact arguments as in the header. I think @_silgen_name is adding the 5th argument. BTW, why does your print_msg Swift declaration is missing the context argument and expects 3 arguments?

kateinoigakukun commented 3 years ago

Sorry for confusing you. Swift default uses swiftcc (Swift Calling Convention) and it requires having swiftself and swifterror arguments on wasm even if the function is not throwable. Please see https://github.com/WebAssembly/tool-conventions/blob/master/SwiftABI.md

I recommend using @_cdecl instead of @_silgen_name to make the function to have C Calling Convention.

MaxDesiatov commented 3 years ago

But @_cdecl is meant to be used only for exported functions, not imported ones, isn't it?

kateinoigakukun commented 3 years ago

Yes, we should add a way to import functions as C function without C code. Until that, we need to use C module with SwiftPM.

And also, we should mention this in our book. Thank you @cohix for reporting this 😄

MaxDesiatov commented 3 years ago

We shouldn't recommend @_silgen_name for importing functions in the SwiftWasm book then, right?

kateinoigakukun commented 3 years ago

Absolutely right.

cohix commented 3 years ago

@MaxDesiatov The context param is used by the Wasmer Go extension and is not exposed to the module, I should have mentioned that in the issue.

Thanks for the explanation! Can we leave this open until a new annotation exists for importing a C-Style function?

MaxDesiatov commented 3 years ago

I think it's more related to #1503, but I'll keep this one open until we update the documentation.

cohix commented 3 years ago

Fair enough, thanks for taking a look.

MaxDesiatov commented 3 years ago

No problem, let us know if you have any other problems, questions or suggestions!