Wasm Support

@Joe_Groff Hi!
While I was fixing the rest of failing test suites, I found that another issue for ABI.
As described here, Swift ABI allows using non-generic function as generic function directly.

On WebAssembly runtime, this ABI causes signature mismatch between callee and caller.

Unlike throws and non-throws, this extra generic parameter doesn't have special attribute, so it's hard to lower them as I did for swifterror.

However as far as I investigated, there is only one use case for this ABI, only KeyPath uses it. I've patched to add extra parameter always to match signatures and this patch makes test/stdlib/KeyPath.swift succeeded.

https://github.com/swiftwasm/swift/pull/252

Do you know other use cases of this optional generic parameter?

In addition, I found extra subscript indices are also passed optionally in KeyPath getter and setter, as same as generic parameter.
Does Swift5 ABI allow additional argument generally? Is this additional argument ABI used in other places?

3 Likes

Adding an extra argument to nongeneric key path entry points is the right thing to do.

Regarding key paths, their weird calling convention is also an issue for optimization, so we may introduce a SIL convention for key path accessors, which would be another marker you could use to lower them to a consistent LLVM function type for wasm:

1 Like

Thanks! I vote that SIL convention for key path accessors.

Just to confirm, do you mean that extra generic argument and extra indices are only used for KeyPath?

Yeah, I don't know of anywhere else that we expect generic and nongeneric functions to have compatible ABIs. If we add such cases in the future, they should be thunkable for wasm targets.

3 Likes

An update on the current status: if you don't care about binary size, it's more or less usable right now as in this demo. Swift can't run dead code elimination on unused protocol conformances yet, so the minimum produced binary size is ~10M raw and ~1.5M when optimized and compressed with 3rd-party tools, as tracked in swiftwasm/swift#7. Building with SwiftPM works, as long as you don't use Foundation or Dispatch due to a few technical reasons (swiftwasm/swift#592, swiftwasm/swift#658, swiftwasm/swift#647), but I hope that a minimalistic bare-bones subset of Foundation can alleviate that pain in the meantime.

Interacting with DOM works through JavaScriptKit built by @kateinoigakukun, also big thanks to him for the Game of Life demo. I honestly didn't expect that we actually have SwiftPM and DOM interaction working at this point before I saw the demo in action :star_struck:

swift test doesn't work yet, but I was able to get a subset of XCTest without expectations, waiters and parallel testing compiling, but not working yet due to a library path issue on Linux. I think I got it working on macOS, but need to verify that with a proper snapshot build. XCTest is one of my top priorities right now, as lack of XCTest blocks people from verifying how well their libraries work when compiled by SwiftWasm.

Overall, I think it's in the state now where any help from the community would be greatly appreciated. Everyone can now install the SwiftWasm toolchain and SDK locally with swiftenv and check if their package works. I hope to get a GitHub action with the toolchain preinstalled working ASAP so that people can start adding this to their CI. Now that upstream 5.3 has been branched, I'd like to start making 5.3 SwiftWasm snapshots, which hopefully converge to something stable by the time upstream Swift 5.3 toolchain is released. Upstreaming the changes would also tremendously help, as it would reduce the maintenance burden we have due to re-appearing merge conflicts. Technical writing and doing basic "DevRel tasks" is also something that would help a lot. I personally work on this full-time right now, but would be deeply grateful for any help and contributions.

Thanks for reading this :slightly_smiling_face:

56 Likes

Thanks for the update, this is amazing progress!

2 Likes

This is fantastic! Is there any low-hanging fruit that interested folks could tackle in the area of code size? It seems like the kind of thing where having many eyes on it could make some easy "wins" possible.

Doug

This has been previously discussed to some extent in the LTO GSoC thread, but I myself mostly have been focusing on the infrastructure part of SwiftWasm, so I'd rather avoid retelling things I don't know well. I saw @kateinoigakukun have been doing some work and research on this, you can see his posts in that thread. I also know he recently submitted a PR that to me seems to be related to this, but again, I don't have enough expertise in that area to provide more details.

1 Like

Great work! The topic of dead protocol conformances has come up in our own performance analysis of Swift binaries as a general problem for code size of Swift binaries, so progress on that front would not only benefit wasm but all targets Swift supports.

11 Likes

Is it possible to use WASM to access ARKit from existing browsers (Safari and Chrome)?

Hi @unnanego, as I've answered your question here a couple of days ago, there is no way to access ARKit from any browser, neither from WebAssembly, nor from JavaScript. ARKit is not a browser API, but a native API. Additionally, there would be no benefit in using it from browsers, since you can already build a native Swift app and call ARKit directly with all the added benefits of native apps, such as better performance, access to multi-threading, ability to optimize for a specific device, access to the rest of the native APIs etc.

1 Like

oh, sorry, couldn't find that topic for some reason, so asked again. thanks for the answer. There is huge benefit in using it in a browser, because nobody wants to install the app for a 30 seconds experience. This is why 8th wall, for example, charges its users an astonishing $3000 per month.

If the experience is so time-limited, I doubt there's anything that ARKit can do that the USDZ format can't in 30 seconds (usually plane detection on an average device takes about 30 seconds to settle in a random environment). Also, I highly doubt that ARKit (or a similar API) will ever become available in browsers before there's a widely adopted camera API for browsers. How would one operate with a hypothetical AR API if there's no API whatsoever to even receive any data from a camera? Even the most basic API to acquire a user permission to start the camera would be required.

lol: WebXR Device API - Web APIs | MDN

Quick Look doesn't allow any interactivity

I'm aware of WebXR, but it doesn't look like any browsers other than those based on the Chromium engine support it, which makes it completely impractical for any adoption. Even if/when it gains adoption, there is a camera access/privacy API discussed as you can see in this article in "A Note About Privacy" section.

Anyway, this is not only off-topic with regards to WebAssembly, but also not related to Swift, especially as ARKit is not a Swift-specific API. Unless you have a question about WebAssembly or SwiftWasm, I would advise against posting about AR in this topic.

What are the limits of this library. Will this library convert any swift code into swiftwasm? For example if I wrote an app in swiftui would it convert that into webassembly? Probably not right.

But that would be super cool. Right once run almost anywhere ...

The only limits are imposed by your WebAssembly host (which in most cases are just web browsers) and the software ecosystem available. Thus, as was discussed above, if you'd like to port your ARKit app you need comparable browser support (probably based on WebXR, which is not available in Safari yet), and some library that wraps it in an ARKit-compatible API.

We already provide a subset of the SwiftUI API that you can check out at tokamak.dev, and the end goal is to get as close as possible (however unrealistic it may be to get there 100%) to the "tick the checkbox and recompile" experience. But instead of "tick the checkbox" you need to replace import SwiftUI with import TokamakShim, and obviously check if your app makes sense as a browser app and make navigation/layout adjustments for it to work. The latter is applicable to all cross-platform frameworks and apps after all.

4 Likes

Hello, everyone. I want to share the current status of Wasm support of the compiler.

Swift Calling Convention

We sent several patches to LLVM for supporting swiftcc on Wasm, and we've finally removed all workarounds for swiftcc in Swift compiler.

https://reviews.llvm.org/D76049

Relative Pointer

As I talked with Joe Groff above, we had decided to use absolute pointer instead of relative pointer at that time due to missing a location relative relocation type.

However, this is a hacky solution and it will break metadata memory layout on 64bit arch, and also fragile for dynamic linking situation.

So we added a location relative relocation type to Wasm obejct file spec, and implemented it in LLVM and lld. This enabled Swift compiler to emit relative pointer to data symbols.

https://reviews.llvm.org/D96659

But there is still a problem when emitting relative function pointer.
Since WebAssembly is a harvard architecture and its data and code address spaces are completely isolated, so relative offsets between relative pointer itself address and the referent function address couldn't be represented.

To address this, I propose forcing relative function to always be indirect on harvard architectures. This is similar to GOTed indirectable relative pointer, but it emits indirect pointer even though the reference and referent are in the same image.
Of course, this indirection would add some amount of runtime performance and size overheads for extra loading and trampoline indirect pointers in data, but as far as I understand, those relative function pointer resolutions are not in performance-critical areas (correct?).

WDYT this approach, runtime people? it would be appreciated if someone could review the change.
CC: @Joe_Groff, @John_McCall
https://github.com/apple/swift/pull/41995/

16 Likes

Is it possible to take the addresses of functions relative to some other per-module reference point? Using the GOT unconditionally would maintain consistency with other platforms, but is overall less efficient than using absolute addresses in the first place, so if it's possible to still get some benefit from the 32-bit direct relative representation.

1 Like