-
Notifications
You must be signed in to change notification settings - Fork 925
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
Compiled function with arguments has wrong signature #3010
Comments
In Go, a For returns values, Does this make sense? |
Ah. Yet this is not going to work for my use case. Let me explain what I want to do. I want to allow other teams to implement an interface, and implement in any language, Golang orJavascript. This will then be executed by importing the module into a Go app. The interface I want is this: func SayHello(person string) string Can |
my 2p: I think string and []byte could be special cased somehow, though when (if) strings are supported natively in wasm, special rules like this will create ambiguity. I might instead keep your signature the same except implement it differently based on arch. Ex. func SayHello(person string) string {
ptr, size := stringToPtr(person)
ptrSize := _SayHello(ptr, size)
ptr = uint32(ptrSize >> 32)
size = uint32(ptrSize)
return ptrToString(ptr, size)
}
// _SayHello implements SayHello using types present in WebAssembly
// core specification 1.0
//
// Note: In TinyGo "//export" on a func is actually an import!
//
//go:wasm-module env
//export SayHello
func _SayHello(ptr uint32, size uint32) (ptrSize uint64)
// ptrToString returns a string from WebAssembly compatible numeric types
// representing its pointer and length.
func ptrToString(ptr uint32, size uint32) string {
// Get a slice view of the underlying bytes in the stream. We use SliceHeader, not StringHeader
// as it allows us to fix the capacity to what was allocated.
return *(*string)(unsafe.Pointer(&reflect.SliceHeader{
Data: uintptr(ptr),
Len: uintptr(size), // Tinygo requires these as uintptrs even if they are int fields.
Cap: uintptr(size), // ^^ See https://github.com/tinygo-org/tinygo/issues/1284
}))
}
// stringToPtr returns a pointer and size pair for the given string in a way
// compatible with WebAssembly numeric types.
func stringToPtr(s string) (uint32, uint32) {
buf := []byte(s)
ptr := &buf[0]
unsafePtr := uintptr(unsafe.Pointer(ptr))
return uint32(unsafePtr), uint32(len(buf))
} As you'll notice this code looks generatable even if not done in tinygo compiler. You can also look at https://github.com/inkeliz/karmem |
ps above was basically cobbled from https://github.com/tetratelabs/wazero/tree/main/examples/allocation/tinygo but I didn't make the source files arch specific (ex to have SayHello defined in a different source file if target=wasi) |
Wow. The answer appears to be “WASM does not support strings”. I’m actually pretty 🤯because it’s such a common language feature I’d just assumed it’s be supported. It’s like buying a car only to find out it does not have windscreen wipers. Yes, you can drive it, but only if you are happy to drive only in the sunshine. |
@alexec yeah that actually is a better way to frame it, basically it doesn't currently and even 2.0 (draft) doesn't support strings. You aren't alone in surprise, basically what some end up realizing is that wasm is mostly focused on core numeric types still though there is hope in the future. There are two specifications some compilers may support ahead of passing the requisite w3c phases, as mentioned in the proposals repo: component-model and stringref. What that means is some compilers may opt-in experimental support ahead of actually ending up in the spec. Meanwhile, what's typical is either a compiler or a code generator translates strings to offset/length pairs, noting that even multiple results aren't supported until WebAssembly 2.0. That said, most runtimes support features needed for multiple results. |
This is such a shame. I had strong expectation about using WASM as an fast (i.e millions of evaluations a second) and portable (i.e. many different language runtime) embedded scripting language and have two strong use cases for it. But lack of string support makes it unusable. 🤷 |
@alexec I suspect it is ok to close this, as tinygo has limited influence on changing the WebAssembly spec ;) |
Yeah, we can't do a lot about it. I hope that the stringref proposal gets some traction, that would allow us to use strings in exported functions. Until then, they are represented as a (pointer, length) pair like in many other languages. |
Wasm functions can return multiple values now. |
Yep, but that isn't a part of a REC spec. Right now, 2.0 which supports that is still a draft. It doesn't mean TinyGo couldn't enable features scheduled for 2.0, but it is a distinct choice to do that. I'm not sure even rust by default will do multiple returns either fwiw. |
Not sure if this was fixed, but as @dgryski mentioned "a package main
func main() {
HelloArg("Hello World!")
}
//export HelloArg
func HelloArg(arg string) JS example: // assuming the wasm module has been instantiated
go.importObject.env = {
'HelloArg': function(arg) {
result = new TextDecoder('utf-8').decode(new Uint8Array(wasm.exports.memory.buffer, arg, 12));
console.log(result) // logs "Hello World!"
}
} |
That's only half true. A string is basically 'HelloArg': function(ptr, len) {
result = new TextDecoder('utf-8').decode(new Uint8Array(wasm.exports.memory.buffer, ptr, len));
console.log(result) // logs "Hello World!"
} Note |
This does not make any sense to me:
Can someone please explain why
HelloArg
andHelloReturn
has these weird parameters?The text was updated successfully, but these errors were encountered: