emscripten-core / emscripten

Emscripten: An LLVM-to-WebAssembly Compiler
Other
25.76k stars 3.3k forks source link

Proposal: __deps: ["$Foo.bar"] for individual properties on objects #20022

Open kripken opened 1 year ago

kripken commented 1 year ago

Example of the hypothetical usage:

  foo__deps: ['$FS.cwd'],
  foo: function(file) {
    work(file, FS.cwd());
  },

Rather than $FS in the above, we depend on $FS.cwd specifically.

The goal here is avoid including an entire huge object all the time. We have such large objects in FS and Browser, for example, and using even a single property forces the entire thing to be added, which this proposal could avoid.

Specifically I found the need for this in WasmFS. WasmFS has much less code in JS than the original FS, but there are many JS APIs that call FS.* APIs, and right now that is very cumbersome. One option has been to rewrite JS code in wasm to avoid JS deps, and I tried that for emscripten_async_wget in a branch, but it turns out to be much less pleasant to write that code in C or C++ than JS (simply because JS has such nice ergonomics for async).

This should not cause any breaking changes. It would only influence new code that uses such deps. Implementation-wise, the deps system would special case a dep of a string X.Y. That already can't be the name of a JS object, so such deps have never existed, unless I'm missing something.

This would take a little work in jsifier, since we'd only be able to emit an object X after knowing all properties that it uses. But I hope that won't be too bad.

I would use this for WasmFS initially, but we could also apply it to Browser and other things and potentially get some nice code size wins.

Thoughts? Alternatives?

sbc100 commented 1 year ago

I worry generally about adding more complexity here. For example, would we then need to deal with the case where one property depend on another. e.g. $FS.cwd__deps: ["$FS.init"],.

One alternative would be to use acorn to parse the JS library files and discover their true dependencies statically at build time based on the symbols they reference. That is a much larger project, but also means we could basically remove all/most of our manual dependencies.

sbc100 commented 1 year ago

For the FS case specifically I seem to remember we have FS_xxx functions to replace the FS.xxx functions. Would that work in your case?

kripken commented 1 year ago

I agree the complexity is a big downside to this.

FS_xxx functions are another option, yeah. Thinking on it, it could look like this:

How does that sound?

sbc100 commented 1 year ago

I agree the complexity is a big downside to this.

FS_xxx functions are another option, yeah. Thinking on it, it could look like this:

  • Code using FS.xxx, like emscripten_async_wget that does FS.mkdirs, would use FS_mkdirs instead.
  • We'd move the code from FS.mkdirs out of the object into a new toplevel function FS_mkdirs.
  • On the FS object, we'd have mkdirs: FS_mkdirs, that is, the property on FS would point to the new toplevel function.

    • For WasmFS we can define those properties only when FORCE_FILESYSTEM (which is effectively what we have now).
    • For the old FS, we'd need to always include them. That means some small increase in code, though maybe closure can inline it anyhow?

How does that sound?

Sounds reasonable yes.