node icon indicating copy to clipboard operation
node copied to clipboard

WASM cache: POC

Open mejedi opened this issue 4 years ago • 3 comments

This is a POC for compiled WebAssembly module cache proposal (#36671).

Checklist
  • [ ] make -j4 test (UNIX), or vcbuild test (Windows) passes
  • [ ] tests and/or benchmarks are included
  • [ ] documentation is changed or added
  • [ ] commit message follows commit guidelines

mejedi avatar Dec 29 '20 09:12 mejedi

@devsnek

I think this seems better suited to userland.

There are some technical difficulties. Please check the overview below. Personally, I don't see how this could be made into a standalone package (I guess this is what you are suggesting), could you please elaborate?

Short version

  1. The only way to deserialise a WASM module in public V8 API is to use the infrastructure supporting .compileStreaming. @addaleax

  2. WebAssembly.compileStreaming is not available, unless WasmStreamingCallback was registered with V8 prior to startup. Makes it challenging to implement the feature as a standalone module.

Compiled WASM module cache is paramount for a good WASM experience, I wonder why you are convinced this should be standalone. It's hard to claim that WASM is out of scope for Node.js, since WASI is already in core.

WebAssembly.compileStreaming workflow

  • Embeder registers a WASM streaming callback. This has to be done prior to V8 startup, otherwise compileStreaming won't be available.
  • compileStreaming(input) will pass the input (resolving the Promise if necessary) to the registered callback, along with WasmStreaming object.
  • The callback should verify that input is something it could stream from, V8 itself doesn't check the input.
  • The callback uses WasmStreaming object to feed the module in:
    • .SetClient(client) — request a notification once the Module is compiled and optimised
    • .SetUrl(url)
    • .SetCompiledModuleBytes(bytes) — pass the previously compiled and optimised module
    • .OnBytesReceived(bytes) — transfer a chunk
    • .Finish()
    • or .Abort()
  • Once .Finish() was called, V8 starts Tier 1 compiler.
  • When Tier 1 completes, the Promise returned from .compileStreaming resolves, and the Module becomes available. It's not optimised yet.
  • Tier 2 continues in the background.
  • Tier 2 completes, V8 transparently replaces the Module code with the optimised version.
  • A client, if registered with WasmStreaming.SetClient, is notified. It could extract the optimised compiled module bytes and save it to cache. Only optimised version is cacheable.

Concerning WebAssembly.compileStreaming (sidenote)

Node.js doesn't expose .compileStreaming at the moment. As a side effect of the proposed changes, it gets exposed. This is probably wrong. According to the spec, is is taking a Request object. There's no such thing in Node.js.

mejedi avatar Dec 29 '20 14:12 mejedi

I would imagine V8 could be modified to support caching in WebAssembly.compile. In that case, the callback wouldn't need to be registered before the context is created, and you could do it from userland.

devsnek avatar Dec 29 '20 14:12 devsnek

See https://github.com/nodejs/node/issues/36671#issuecomment-768257129.

tniessen avatar Jan 27 '21 12:01 tniessen