To what extent writing your code in WebAssembly (eg Rust) can help with those points (eg structs in C argument). It would still run in a JS VM so I'm guessing a bit, but not to the full extent?
WebAssembly helps a lot, but doesn’t solve the jit issue.
WebAssembly also introduces its own issues since it’s a BYORT system (bring your own runtime). So, there’s more to JIT (your language’s whole runtime) and more to hold in memory (your language’s whole runtime). You might say, “but pizlonator, every language has a runtime”, to which I’d say: yes but usually that shit gets shared by every running instance somehow. In WebAssembly every instance pays for its runtime’s memory footprint and it’s quite likely that every instance has a different runtime so the code isn’t shared either. Basically, WebAssembly is knee-capped on memory footprint by design. JS isn’t.
Your comment seems substantially misinformed or inapplicable.
WebAssembly has no truck with JIT. Just-In-Time compilation is all about not performing optimisation ahead of time, but only doing it when the code in question is used, and guiding the optimisation by how the code is being used. In WebAssembly, the conversion from the binary .wasm format to machine code is a comparatively lightweight process with no real optimisation of this form: rather, such optimisations must be done as part of producing that .wasm blob (in regular compilation possibly with profile-guided optimisation to go even further than JIT can).
So instead, when you’re using something like Rust (as distinct from, say, compiling CPython or V8 to WASM), what you’ve got is a fairly small amount of what you’d probably call runtime code (allocator, panic mechanism, str, Vec<_>, some other parts of the std crate), probably something like 25KB (or with a little care and compromise, more like 5KB) except when Unicode tables are required, compiled from WASM byte code to similarly-sized (though I don’t know the real ratio) machine code faster than it can be downloaded. That’s code memory usage; for the data memory usage, well, your Rust/WASM will normally blow your JavaScript out of the water there with much more efficient packing of data into memory, even if you’ve got a fair bit of overallocation.
The fact of the matter is that the runtime parts which can be shared for JavaScript are actually not all that large, and routinely dwarfed by included libraries (React, &c.). WebAssembly is by no means knee-capped on memory footprint; rather, so long as you’re using it in a sane way (Rust, standard WASM optimisation and code-shrinking techniques, that kind of thing), there’s a pebble in the way that you’ll notice if you’re a beetle, but if you’re even rabbit-sized you probably won’t even notice it.
As regards pbadenski’s comment: WebAssembly does not run in the JavaScript virtual machine, it’s a completely separate thing that is merely able to call and be called from JavaScript via a foreign function interface. The backing memory buffer may also be accessed from JavaScript, but that’s immaterial in the consideration.
The wasm blob has to undergo the hardest parts of optimization to get native code from it. You need to select instructions and allocate registers. Those things are time consuming; they are on the same order of magnitude of time consumption than most full compiler pipelines.
Compiling wasm to native is only faster than downloading if you compile without optimization. That’s common in wasm VMs but then there’s an optimizing JIT that runs adaptively later, just like a JS or Java VM would do.
The fact that JS VMs share the ICU implementation between instances is a huge deal. That’s not the only thing that gets shared. Also, it’s not about just sharing code; it’s about sharing memory for the runtime’s state and for allowing elastic reuse of space for objects. In wasm the sharing is page granularity at best.
WebAssembly also introduces its own issues since it’s a BYORT system (bring your own runtime). So, there’s more to JIT (your language’s whole runtime) and more to hold in memory (your language’s whole runtime). You might say, “but pizlonator, every language has a runtime”, to which I’d say: yes but usually that shit gets shared by every running instance somehow. In WebAssembly every instance pays for its runtime’s memory footprint and it’s quite likely that every instance has a different runtime so the code isn’t shared either. Basically, WebAssembly is knee-capped on memory footprint by design. JS isn’t.