Skip to content
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

Blog entry for new JSPI API #767

Merged
merged 27 commits into from
Jun 4, 2024
Merged
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
35626ee
Blog entry for new JSPI API
fgmccabe May 29, 2024
51ecf31
Update src/blog/jspi-newapi.md
fgmccabe May 31, 2024
973d214
Update src/blog/jspi-newapi.md
fgmccabe May 31, 2024
2719d3a
Update src/blog/jspi-newapi.md
fgmccabe May 31, 2024
aa49c7c
Update src/blog/jspi-newapi.md
fgmccabe May 31, 2024
816d469
Update src/blog/jspi-newapi.md
fgmccabe May 31, 2024
9a4a9fe
Update src/blog/jspi-newapi.md
fgmccabe May 31, 2024
0b73c55
Update src/blog/jspi-newapi.md
fgmccabe May 31, 2024
0673e33
Update src/blog/jspi-newapi.md
fgmccabe May 31, 2024
1f2ac67
Update src/blog/jspi-newapi.md
fgmccabe May 31, 2024
a06550c
Update src/blog/jspi-newapi.md
fgmccabe May 31, 2024
42d7833
Update src/blog/jspi-newapi.md
fgmccabe May 31, 2024
6048035
Update src/blog/jspi-newapi.md
fgmccabe May 31, 2024
762a48f
Update src/blog/jspi-newapi.md
fgmccabe May 31, 2024
27ed700
Update src/blog/jspi-newapi.md
fgmccabe May 31, 2024
5df6492
Update src/blog/jspi-newapi.md
fgmccabe May 31, 2024
ca32bea
Update src/blog/jspi-newapi.md
fgmccabe May 31, 2024
347dec2
Update src/blog/jspi-newapi.md
fgmccabe May 31, 2024
d5cf036
Update src/blog/jspi-newapi.md
fgmccabe May 31, 2024
2f1ea11
Update src/blog/jspi-newapi.md
fgmccabe May 31, 2024
29b33a7
Update src/blog/jspi-newapi.md
fgmccabe May 31, 2024
5256008
Update src/blog/jspi-newapi.md
fgmccabe May 31, 2024
84e42d3
Update src/blog/jspi-newapi.md
tomayac May 31, 2024
fe008ed
Additional change following reviewer remarks.
fgmccabe May 31, 2024
fb7ed1b
Fix chrome milestones
fgmccabe May 31, 2024
3c60e6d
Add section on detecting which JSPI is enabled.
fgmccabe May 31, 2024
240526d
Update src/blog/jspi-newapi.md
fgmccabe Jun 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 106 additions & 0 deletions src/blog/jspi-newapi.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
---
title: 'WebAssembly JSPI has a new API'
description: 'We explain the new API for JSPI'
fgmccabe marked this conversation as resolved.
Show resolved Hide resolved
author: 'Francis McCabe, Thibaud Michaud, Ilya Rezvov, Brendan Dahl'
date: 2024-05-28
tags:
- WebAssembly
---
WebAssembly’s JavaScript Promise Integration (JSPI) API has a new API, available in Chrome release M126. We talk about what has changed, how to use it with Emscripten, and what is the roadmap for JSPI.

JSPI is an API that allows WebAssembly applications that use *sequential* APIs to access Web APIs that are *asynchronous*. Many Web APIs are crafted in terms of JavaScript `Promise`s: instead of immediately performing the requested operation they return a `Promise` to do so. On the other hand, many applications compiled to WebAssembly come from the C/C++ universe which is dominated by APIs that block the caller until they are completed.
fgmccabe marked this conversation as resolved.
Show resolved Hide resolved

JSPI hooks into the Web architecture to allow a WebAssembly application to be suspended when the `Promise` is returned and resumed when the `Promise` is resolved.

You can find out more about JSPI and how to use it [here](https://v8.dev/blog/jspi) and the specification itself is [here](https://github.com/WebAssembly/js-promise-integration).
fgmccabe marked this conversation as resolved.
Show resolved Hide resolved

## What is new?

### The end of `Suspender`s
fgmccabe marked this conversation as resolved.
Show resolved Hide resolved

In January 2024, the Stacks sub-group of the Wasm CG [voted](https://github.com/WebAssembly/meetings/blob/297ac8b5ac00e6be1fe33b1f4a146cc7481b631d/stack/2024/stack-2024-01-29.md) to amend the API for JSPI. Specifically, instead of an explicit `Suspender` object we will use the JavaScript/WebAssembly boundary as the delimiter for determining what computations are suspended.
fgmccabe marked this conversation as resolved.
Show resolved Hide resolved

The difference is fairly small but potentially significant: when a computation is to be suspended it is the most recent call into a wrapped WebAssembly export that determines the 'cut point' for what is suspended.
fgmccabe marked this conversation as resolved.
Show resolved Hide resolved

The implication of this is that a developer using JSPI has a little less control over that cut point. On the other hand, not having to explicitly manage `Suspender` objects makes the API significantly easier to use.

### No more `WebAssembly.Function`

Another change is to the style of the API. Instead of characterizing JSPI wrappers in terms of the `WebAssembly.Function` constructor, we provide specific functions and constructors.

This has a number of benefits:

- It removes dependency on the [*Type Reflection Proposal*](https://github.com/WebAssembly/js-types), and
- it makes tooling for JSPI simpler: the new API functions no longer need to refer explicitly to the WebAssembly types of functions.
fgmccabe marked this conversation as resolved.
Show resolved Hide resolved

This change is enabled by the decision to no longer have explicitly referenced `Suspender` objects.

### Returning without suspending

A third change refers to the behavior of suspending calls. Instead of always suspending when calling a JavaScript function from a suspending import, we only suspend when the JavaScript function actually returns a `Promise`.

This change, while apparently going against the [recommendations](https://www.w3.org/2001/tag/doc/promises-guide#accepting-promises) of the W3C TAG, represents a safe optimization for JSPI users. It is safe because JSPI is actually taking on the role of a *caller* to a `Promise` returning function.
fgmccabe marked this conversation as resolved.
Show resolved Hide resolved

This change will likely have minimal impact on most applications; however, some applications will see a notable benefit by avoiding unnecessary trips to the browser event loop.
fgmccabe marked this conversation as resolved.
Show resolved Hide resolved

### The new API

The API is pretty simple: there is a function that takes a function exported from a WebAssembly module and converts it into a `Promise` returning function:
fgmccabe marked this conversation as resolved.
Show resolved Hide resolved

```js
Function Webassembly.promising(Function wsFun)
```

Note that, although the argument is typed as a `Function` — i.e., a JavaScript function — it is actually restricted to WebAssembly functions.
fgmccabe marked this conversation as resolved.
Show resolved Hide resolved

On the suspending side, we have a new class `WebAssembly.Suspending`, together with a constructor that takes a JavaScript function as argument. In WebIDL this is written:
fgmccabe marked this conversation as resolved.
Show resolved Hide resolved

```js
interface Suspending{
constructor (Function fun);
fgmccabe marked this conversation as resolved.
Show resolved Hide resolved
}
```

Note that this API has an asymmetric feel to it: we have a function that takes a WebAssembly function and returns a new promising (sic) function; whereas to mark a suspending function we enclose it in a `Suspending` object. This reflects a deeper reality about what is happening under the hood.
fgmccabe marked this conversation as resolved.
Show resolved Hide resolved

The suspending behavior of an import is intrinsically part of the *call* to the import: i.e., some function inside the instantiated module calls the import and suspends as a result.

On the other hand, the `promising` function takes a regular WebAssembly function and returns a new one that can respond to being suspended and which returns a `Promise`.

### Using the new API

If you are an Emscripten user, then using the new API will typically involve no changes to your code. You must be using a version of emscripten that is at least 3.1.61, and you must be using a version of Chrome that is at least 126.0.6478.17 (milestone 126).
fgmccabe marked this conversation as resolved.
Show resolved Hide resolved

If you are rolling your own integration, then your code should be significantly simpler. In particular, it is no longer necessary to have code that stores the passed-in `Suspender` object (and retrieve it when calling the import). One can simply use regular sequential code within the WebAssembly module.
fgmccabe marked this conversation as resolved.
Show resolved Hide resolved

### The old API

The old API will continue to operate at least until 10/29/2024 (Chrome M128). After that we plan on removing the old API.
fgmccabe marked this conversation as resolved.
Show resolved Hide resolved

Note that Emscripten itself will no longer support the old API as of version 3.1.61.

## What is happening with JSPI?

### Implementation aspects

The biggest change to JSPI that we are working on is actually invisible to most programmers: so-called growable stacks.

The current implementation of JSPI is based on allocating stacks of a fixed size. In fact, the allocated stacks are rather large; because we have to be able to accomodate arbitrary WebAssembly computations which may require deep stacks to handle recursion properly.
fgmccabe marked this conversation as resolved.
Show resolved Hide resolved

However, this is not a sustainable strategy: we would like to support applications with millions of suspended coroutines; this is not possible if each stack is 1Mb in size.
fgmccabe marked this conversation as resolved.
Show resolved Hide resolved
tomayac marked this conversation as resolved.
Show resolved Hide resolved

Growable stacks refers to a stack allocation strategy that allows a WebAssembly stack to grow as needed. That way, we can start with very small stacks for those applications that only need small stack space and grow the stack when the application runs out of room (otherwise known as stack overflow).
fgmccabe marked this conversation as resolved.
Show resolved Hide resolved

There are several potential techniques for implementing growable stacks. One that we are investigating is segmented stacks. A segmented stack consists of a chain of stack regions — each of which has a fixed size, but different segments may have different sizes.

Note that while we may be solving the stack overflow issue for coroutines we are not planning to make the main or central stack growable. Thus, if your application runs out of stack space, growable stacks will not fix your problem unless you use JSPI.
fgmccabe marked this conversation as resolved.
Show resolved Hide resolved

### The standards process

As of publication, there is an origin trial for JSPI — see [here](https://v8.dev/blog/jspi-ot) — that is active. The new API will be live during the remainder of the origin trial — available with Chrome M126.
fgmccabe marked this conversation as resolved.
Show resolved Hide resolved

The previous API will also be available during the origin trial; however, it is planned to be retired shortly after Chrome M132.

After that, the main thrust for JSPI revolves around the standardization process. JSPI is currently (at publication time) in phase 3 of the W3C Wasm CG process. The next step, moving to phase 4, marks the crucial adoption of JSPI as a standard API for the JavaScript and WebAssembly.
fgmccabe marked this conversation as resolved.
Show resolved Hide resolved

We would like to know what you think about these changes to JSPI! Join the discussion at the W3C WebAssembly Community Group [repo](https://github.com/WebAssembly/js-promise-integration).
fgmccabe marked this conversation as resolved.
Show resolved Hide resolved
Loading