Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Add Asyncify support#107

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
yonihemi wants to merge12 commits intoswiftwasm:main
base:main
Choose a base branch
Loading
fromyonihemi:asyncify
Open

Conversation

@yonihemi
Copy link
Member

@yonihemiyonihemi commentedNov 5, 2020
edited
Loading

What this adds

Calls out to modules withwasm-opt's--asyncify pass to unwind and rewind the module's call stack when we want to put Swift execution to sleep while allowing incoming events to be handled by JavaScript.

Further Reading

Alon Zakai's Blog
Alon Zakai's Talk
Binaryen Docs
Experimental JS wrapper from Google

Concerns

  • This adds a bit of complexity on the JS runtime side, especially the need to provide a 'restart' method for re-entering module execution. Should not affect existing usage as all additions are optional.
  • At Swift build time, there is no way of knowing if module will be asyncified so no way to block usage of new methods. The Asyncify pass is extremely slow as well, so not a good candidate to add e.g. to carton's build process.

MaxDesiatov, lin7sh, lin72h, and ramoncerdaquiroz reacted with thumbs up emoji
@yonihemiyonihemi added the enhancementNew feature or request labelNov 5, 2020
@swiftwasmswiftwasm deleted a comment fromMaxDesiatovNov 5, 2020
@MaxDesiatov
Copy link
Member

Thanks for this work, and I appreciate you mentioned the concerns. I'm not sure how it would compare totheasync/await support that's coming in Swift 5.4 likely in spring 2021. But we'd definitely want to supportasync/await together withthe structured concurrency proposal in SwiftWasm in general and JavaScriptKit specifically.

It would make sense to have some utilityasync function on theJSPromise class that allows Swift code toawait for a completion. At least in my current understanding that's not very hard to implement. I'd like to start experimenting with this as soon it's available upstream and we have that merged in, hopefully in the next few months.

Is it worth investing inasyncify in addition to tha nativeasync/await support in Swift? What kind of use cases do you see forasyncify at the moment?

Comment on lines 632 to 653
swjs_sleep:(ms:number)=>{
syncAwait(delay(ms));
},
swjs_sync_await:(
promiseRef:ref,
kind_ptr:pointer,
payload1_ptr:pointer,
payload2_ptr:pointer
)=>{
constpromise:Promise<any>=this.heap.referenceHeap(promiseRef);
syncAwait(promise,kind_ptr,payload1_ptr,payload2_ptr);
},
swjs_sync_await_with_timeout:(
promiseRef:ref,
timeout:number,
kind_ptr:pointer,
payload1_ptr:pointer,
payload2_ptr:pointer
)=>{
constpromise:Promise<any>=this.heap.referenceHeap(promiseRef);
syncAwait(promiseWithTimout(promise,timeout),kind_ptr,payload1_ptr,payload2_ptr);
},

Choose a reason for hiding this comment

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

Can we expose onlyswjs_sync_await to minimize runtime functions? I think others can be implemented on Swift side.

yonihemi reacted with thumbs up emoji
Copy link
MemberAuthor

Choose a reason for hiding this comment

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

await_with_timeout definitely can be removed and easily implemented by callers. Not sure about the sleep one, assetTimout doesn't return a proper Promise implementing that from Swift side would be kind of ugly, and sleep is the most useful for imported c code.

Copy link
MemberAuthor

@yonihemiyonihemiJan 8, 2021
edited
Loading

Choose a reason for hiding this comment

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

I've removed the withTimeout function.@kateinoigakukun What do you think would be best regarding sleep?

  1. Leave as is. Cons: Extra C function, extra JS function.
  2. Have Swift construct thedelay promise on first request with JSPromise-JSTimer code, cache it atJSObject.global for future use, then call it. Cons: Swift code will be ugly and less efficient, polluting global namespace.
  3. Remove it from the Swift API and let users define their global JS promise if they want. Cons: Whilesleep is a special case ofwait, it is arguably more useful and a surprise to users when they can't find it. And while adding the global JS function is trivial if you know about it, connecting these dots cold be difficult to newcomers. Plus, I hope actual C code can use it directly.
    Or any other ideas?

@yonihemi
Copy link
MemberAuthor

Thanks for reviewing this!
Async/await is exciting but its implementation in SwiftWasm might not be related or solve the exact same issue this is solving.

Let's take this code snippet for example:

publicvardogs:[Dog]{iflet dogs= _cachedDogs{return dogs}guardlet url=Bundle.module.url(forResource:"dogs", withExtension:"json"),let data=try?Data(contentsOf: url),let dogs=try?JSONDecoder().decode([Dog].self, from: data)else{fatalError()}    _cachedDogs= dogsreturn dogs}

One can argue it has some glaring mistakes but no doubt similar code appears in many code bases.
Focusing on theurl(forResource..) andData(contentsOf:) calls, they are bothsynchronous, but if we wanted to fulfill them from a JS host to Wasm we'd have to useasync JS methods. Without asyncify there is no way for us to do that (the problem of having the Wasm module pause while still processing incoming events). Also applies as well toimported C code. (Side note: 'Asyncify' might not be the best name to a framework that does the exact opposite).

A year from today, will there be 100% coverage for all methods with newasync counterparts and wide adoption in the industry? Maybe. For this example, any code that relies ondogs will have to change to async as well, probably down the entire call tree of any app, so I don't see that happening so soon.

I expect the async/await actual implementation for SwiftWasm to be more straightforward than this - matching async expectation with async external implementations (vs. this fix - matching sync expectations with external async implementations), and in any case not interfering with that implementation.

I wish there was an easy way to have this as an entirely different package or as a plugin of some sort, but this other package would have to reimplement most of JavaScriptKit, or we'd have to expose a bunch of internal implementation details, which would not be great either.

@MaxDesiatov
Copy link
Member

I had another look at this and actually think it would be a really useful addition after all.

Firstly, it would potentially allow us writing async tests for DOM so that they look synchronously and work with standard XCTest without waiting (pardon the pun) until it supportsasync/await.

Secondly, I'm thinking about apps that could utilize Wasm for plugins written in any language. These plugins could be long running or resource intensive, or both. At the same time, it would be useful to allow loading a lot of such plugins, potentially hundreds of them, but allowing them to run concurrently without blocking each other. Creating a dedicated OS thread for every plugin instance is impractical, that's where Asyncify comes into play.

A plugin host could provide its ownyield_to_host() function, which would be equivalent tosleep() in the basic Asyncify example, but making a plugin instance sleep indefinitely until the plugin host wakes it up at some later point.

Do we currently have anything that blocks this PR? I think after this is merged, we could add--asyncify flag or--optimize asyncify option tocarton.

@yonihemi
Copy link
MemberAuthor

There is a bug with processing incoming events while suspended. Let me push a fix, though not before tomorrow.
Even so, I'm not sure about merging this. I have some thoughts on the position of JSKit/HostKit on a lower level and as an augmentation to WASI. I'll try and jot it down more coherently and we can discuss.

Meanwhile about the long build times - my hypothesis is we might be able to leverageasyncify-imports (akaasyncify+list), limited to 1 method as@kateinoigakukun suggested, in a prebuilt Foundation+JSKit module, then ChibiLink it with a (fast) build of a project. Haven't made much progress and still not convinced it's doable.

MaxDesiatov reacted with thumbs up emoji

@yonihemiyonihemi marked this pull request as ready for reviewJanuary 20, 2021 13:32
@kateinoigakukun
Copy link
Member

@yonihemi Could you add some test cases to ensure that asyncify works fine?

yonihemi reacted with thumbs up emoji

@yonihemiyonihemi marked this pull request as draftJanuary 30, 2021 14:37
@yonihemi
Copy link
MemberAuthor

Made aworking sample.

kateinoigakukun reacted with eyes emoji

@yonihemiyonihemi marked this pull request as ready for reviewJanuary 31, 2021 07:12
@MaxDesiatov
Copy link
Member

@kateinoigakukun what are your thoughts on this? I'm thinking of tagging a new version, so I'm wondering if that should be a minor 0.10.1 without this change, or a major-ish 0.11.0 with this included if there's any chance for it to be reviewed and merged soon?

ramoncerdaquiroz reacted with heart emoji

@kateinoigakukun
Copy link
Member

I'm sorry to have kept you waiting. At least, we can't merge this feature without more test suites within this repository.
So tagging a minor version without this PR would be reasonable at this time.

@yonihemi
Copy link
MemberAuthor

yonihemi commentedApr 28, 2021
edited
Loading

Looks like I haven't managed to present the case for Asyncify successfully. Not surprising, as this was the fate of similar patches in most projects except Emscripten itself. It's a tough sell.
I think best for now would be to close this PR. I'll of course keep my branch alive as I'm using it.
In future, if someone else comes up with the need for sync C / Swift we can pick it up.

ramoncerdaquiroz reacted with eyes emoji

@MaxDesiatov
Copy link
Member

I hope there's a way to keep this open and eventually get merged.@kateinoigakukun is the amount of test coverage your only concern here?

ramoncerdaquiroz reacted with thumbs up emoji

@kateinoigakukun
Copy link
Member

@yonihemi@MaxDesiatov

I concern about these two things:

  1. Low test coverage

We need to test the feature more because there are many things to be considered:

  • What happens when asyncify buffer is overflow
  • What happens when exported Swift function is called while sieeping
  • etc...
  1. async / await covers almost the same use cases as Asyncify (in my understanding)

If the Wasm side wants a synchronous API, but the actual JS implementation requires asynchronous operations, asyncify is useful and async/await cannot be used in that case.
But unlike C, it is very easy to make a synchronous function an asynchronous function in Swift by just putting async keyword, so even in such a use case, we can solve it by making the API on the Swift side asynchronous.
In addition, providing features with similar use cases at the same time can be confusing to users. So, instead of implementing it directly in JSKit, I think it's better to make the Asyncify things an optional feature to avoid confusion. Explicit importing or opt-in operation can imply to users that they need to prepare with wasm-opt.

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment

Reviewers

@kateinoigakukunkateinoigakukunAwaiting requested review from kateinoigakukun

At least 1 approving review is required to merge this pull request.

Assignees

No one assigned

Labels

enhancementNew feature or request

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

3 participants

@yonihemi@MaxDesiatov@kateinoigakukun

[8]ページ先頭

©2009-2025 Movatter.jp