How to deserialise a WASM module with public V8 apis

219 views
Skip to first unread message

Nick Zavaritsky

unread,
Dec 31, 2020, 5:13:44 AM12/31/20
to v8-dev
Hi!

There's currently no compiled module cache for WASM modules in Node.js. I've started an effort to make one (https://github.com/nodejs/node/issues/36671). There's a POC already.

The POC hijacks WebAssembly.compileStreaming. It uses v8::WasmStreaming::SetCompiledModuleBytes to deserialise a cached module. Please let me know if there's a cleaner approach.

Best,
N

Nick Zavaritsky

unread,
Dec 31, 2020, 5:31:59 AM12/31/20
to v8-dev
Forgot to mention that implementing a standards-conforming WebAssembly.compileStreaming in Node.js is probably not an option. There's no Request in Node.js to start with. The feature is covering local files only. Hence the proposal introduces a cache-enabled loader as a custom api (e.g. require("wasm/cache").loadFile(path) ).

The problem is that there's a single global WasmStreaming callback. Hijacking it makes future implementation of the proper WebAssembly.compileStreaming unnecessary cumbersome (if it comes to be). Even though Node.js itself probably isn't going to need it in foreseeable future, Node is often embedded in larger projects (e.g. Electron). Barring them from having this opportunity makes Node.js maintainers unhappy.

Best,
N

Clemens Backes

unread,
Jan 5, 2021, 6:01:08 AM1/5/21
to v8-dev
V8 used to have an API to directly create a Wasm module from serialized bytes. It was removed in https://crrev.com/c/2033171. We could bring it back if there is use for it (it would need some tests then, which were missing before).

--
--
v8-dev mailing list
v8-...@googlegroups.com
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to v8-dev+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/v8-dev/9c27c1ec-61c7-486c-abb5-138a2d7feac4n%40googlegroups.com.


--

Clemens Backes

Software Engineer

clem...@google.com

Google Germany GmbH

Erika-Mann-Straße 33

80636 München


Geschäftsführer: Paul Manicle, Halimah DeLaine Prado

Registergericht und -nummer: Hamburg, HRB 86891

Sitz der Gesellschaft: Hamburg


Diese E-Mail ist vertraulich. Falls sie diese fälschlicherweise erhalten haben sollten, leiten Sie diese bitte nicht an jemand anderes weiter, löschen Sie alle Kopien und Anhänge davon und lassen Sie mich bitte wissen, dass die E-Mail an die falsche Person gesendet wurde.


This e-mail is confidential. If you received this communication by mistake, please don't forward it to anyone else, please erase all copies and attachments, and please let me know that it has gone to the wrong person.

Nick Zavaritsky

unread,
Jan 5, 2021, 6:42:40 AM1/5/21
to v8-dev
Hi Clemens,

Thank you for the reply. I am reading your response as a confirmation that indeed there is currently no other way to deserialise a WASM module apart from using compileStreaming.

I dunno if reviving the API you are referring to is enough. We need to find out if the top-tier compiler has completed before serialising, don't we?

CompileStreaming handles that. It would be nice if it was possible to invoke it giving a streaming callback as an argument via a C++ API.

Clemens Backes

unread,
Jan 5, 2021, 7:12:20 AM1/5/21
to v8-dev
Yes, compileStreaming is the only API that supports deserialization, currently. But it sounds like you are not really doing streaming compilation, you just want to implement similar functionality for synchronous compilation. In that case, I would propose to extend the V8 API to support your use case, instead of using an existing but not-quite-fitting API.

Maybe you just need to add two new methods: CompiledWasmModule::AddTopTierCompiledCallback and (static) CompiledWasmModule::Deserialize.
Let me know if you need help adding those to V8. I could send you a patch for prototyping locally, to figure out if this approach works well for Node.js.

Andreas Haas

unread,
Jan 5, 2021, 9:14:21 AM1/5/21
to v8-dev
Hi Nick,

I agree with Clemens that this is definitely an API that we can add to support your use case, and we don't have it yet because we don't have a user for it yet.

I don't understand yet though how you would like to integrate a compiled module cache for wasm. What kind of JavaScript code would a user write to access the cache? Would the user just write normal JavaScript code with `new WebAssembly.Module()` and `WebAssembly.compile()`, and we should do a cache lookup in that case? Or would there be explicit commands in the JavaScript code for serialization and deserialization?

As soon as we understand the use case, we can also work on an API to support it.

Cheers, Andreas



--

Andreas Haas

Software Engineer

ah...@google.com

Nick Zavaritsky

unread,
Jan 6, 2021, 6:37:25 AM1/6/21
to v8-dev
Hi Andreas,

> I don't understand yet though how you would like to integrate a compiled module cache for wasm. What kind of JavaScript code would a user write to access the cache? Would the user just write normal JavaScript code with `new WebAssembly.Module()` and `WebAssembly.compile()`, and we should do a cache lookup in that case? Or would there be explicit commands in the JavaScript code for serialization and deserialization?

While having implicit caching in `WebAssembly.compile()` would be super cool, it is probably not feasible, is it? What should the cache key be? A crypto digest would work, but that's slow. A non-crypto quality hash function would have security implications. Using the whole module as a key would require a database.

The next best option is exposing serialisation and deserialisation, so that Node.js could implement a cache-enabled custom API, e.g. loadFromFileAndCompile(path).

It would be nice if it was possible to disable Liftoff for a particular Module. Use case: a utility that's not supposed to run long enough, Turbofan burns CPU cycles but never completes. Also: AOT compilation.

Andreas Haas

unread,
Jan 7, 2021, 5:26:20 AM1/7/21
to v8-dev
Hi Nick,

I agree, it's not clear how to add implicit caching to `WebAssembly.compile()`. Exposing serialisation and deserialisation may be the right way. Making serialisation explicit would make the V8 API design much easier. There is already a test function for that in d8, see https://source.chromium.org/chromium/chromium/src/+/master:v8/src/runtime/runtime-test.cc;l=1421;drc=fef22ea25dcdfe160986317a4fd6239af90864bc. If there should be an unconditional callback whenever TurboFan compilation is finished, that would be much more complicated. We would again run into an identifier problem: When we call the callback, how would the embedder know which WebAssembly module just finished TurboFan compilation?

About disabling Liftoff, this is already implemented. There was an internship project where the intern experimented with compilation hints. The assumption was that there is metadata attached to a WebAssembly module that defines which functions should be compiled with Liftoff, which ones with TurboFan, and which ones should only be compiled lazily. The results looked promising, but the metadata section would better be standardized to avoid incompatibilities on the web. What I want to say is, if you could think of a good API to tell V8 whether Liftoff or TurboFan should be used, it would not be hard to implement, even on a per-function level. The difficult part is the API.

You could also allow a user to set the --no-liftoff flag, either for the whole script execution or just for some time. Changing the flag during compilation could cause problems though.

Cheers,

Reply all
Reply to author
Forward
0 new messages