[HN Gopher] Making JavaScript run fast on WebAssembly
___________________________________________________________________
Making JavaScript run fast on WebAssembly
Author : 0xedb
Score : 142 points
Date : 2021-06-02 15:53 UTC (7 hours ago)
(HTM) web link (bytecodealliance.org)
(TXT) w3m dump (bytecodealliance.org)
| kodablah wrote:
| > So how does this work? Before the code is deployed, as part of
| a build step, we run the JS code using the JS engine to the end
| of initialization.
|
| I also did basically this exact same thing for Go [0] when I
| realized their initialization in WASM was very heavy[1].
| Basically I ran up until the real Go main started which includes
| a ton of runtime package/data initialization, and took a snapshot
| of the data and baked it back into the WASM and removed all the
| pre-main code. Granted this was years ago so I don't know if it
| still works on generated code today, but the idea is the same.
|
| I think languages compiling to WASM, if they can, should run
| their initialization code and snapshot the data. A lot of people
| don't realize the number of init instructions to bootstrap a
| runtime these days. Go alone has thousands of instructions just
| to initialize the unicode tables. Over 4 million instructions
| before main were removed from hello-world Go WASM init by pre-
| processing.
|
| 0 - https://github.com/cretz/go-wasm-bake 1 -
| https://github.com/golang/go/issues/26622
| skratlo wrote:
| And round and round we go
|
| http://www.sbcl.org/manual/index.html#Saving-a-Core-Image
| deathanatos wrote:
| Which reminds me of Emac's unexec():
| https://emacshorrors.com/posts/unexecute.html
|
| (Not sure if that's the best link, but it is easily
| Googleable.)
| tingletech wrote:
| `perlcc` works basically the same way if I understand
| correctly
| bitwize wrote:
| This is also how Emacs optimized its startup: by loading its
| initial Emacs Lisp code and dumping itself together with a heap
| snapshot into a new executable (there is a special API in glibc
| to do just this).
|
| Recently Emacs has moved to a "portable dump" approach which
| saves the heap snapshot separately.
| hackcasual wrote:
| You want to be careful with this technique when payload size
| dominates your application's performance, like on a webpage. I
| was looking into improving Emscripten's pre-execution behavior,
| but found that ended up making perf worse when factoring in
| standard download speeds. The functions it removes are usually
| smaller than the data they add, usually with worse entropy. So
| while JS is faster to execute, it's usually not faster than the
| transfer time.
|
| It gets a bit worse if your initialization code is doing a lot
| of dynamic allocation, as you're shipping
| Softcadbury wrote:
| For the first call maybe, but then with the cache ?
| hackcasual wrote:
| You're really only saving a few milliseconds, and keeping
| cached files small is valuable.
| wffurr wrote:
| You can't ever rely on the browser cache. Hit rates are
| very poor.
|
| Unless maybe you're managing cache yourself with a service
| worker.
| jfrunyon wrote:
| That depends entirely on what you're developing (internal
| vs external etc.) and how frequently the resource will be
| needed.
| baybal2 wrote:
| WASM is slowly, and inevitably becoming Java 2.0, or better to
| say a new Java VM sans Java.
| emteycz wrote:
| Yes, that is more or less the goal - with the major difference
| being cross-industry collaboration - every major player is
| included and even the community has its word.
| kaba0 wrote:
| How is the JEP process not cross-industry collaboration with
| a significant community voice?
| k__ wrote:
| Didn't the Harmony disaster show that Java is a garbage
| fire?
| kaba0 wrote:
| If you mean the Oracle v Google fiasco, it was a legal
| battle on whether it is legal to copy a significant part
| but not exactly the whole of what is called JavaTM.
|
| But Java is one of the few major languages that is
| standard-specified, not specified by the reference
| implementation, the reference impl. is completely open
| source, and the ecosystem is blooming. So, no? It is a
| huge platform running a very very significant chunk of
| all the backend servers.
| pjmlp wrote:
| There were plenty of VMs since the late 50's, even C and C++
| have a couple for them (not talking about anything LLVM
| related).
| jonny_eh wrote:
| I'm so lost. Why are you shipping a JS Engine built for WASM?
| Wouldn't any platform that can run WASM also run JS code?
| skratlo wrote:
| They wants to run JS faster, on platforms where they can run
| Swift/native with zero overhead. As of why? Go figure.
| filleduchaos wrote:
| The gamedev industry will no doubt be shocked to learn that
| they could have just been running native with zero overhead
| instead of implementing and embedding various forms of
| scripting.
| gostsamo wrote:
| Serverless is mentioned a few times in the text of the
| article.
|
| More generally, WASM is promoted as universal bytecode
| virtual machine, so they want to make it "run everything
| everywhere".
| oscargrouch wrote:
| I think WASM will have a great future in the cloud, giving
| cloud providers can offer their services in any programming
| language their users want, running in a secure sandbox.
|
| But i'm not so sure about personal devices. It would be
| very hard to beat Javascript code on the Web in general. So
| i dont know about the general purpose target future in that
| case, i think it will flop, except as a fancy accelerator
| or to virtualize things that was once outside the web.
| ygjb wrote:
| While there will always be the case that highly optimized
| javascript code will be more performant, the flexibility
| and performance of WASM on the web and in browsers means
| that a significant number of high impact products and
| services have already made the jump to using WASM in part
| or in full.
|
| https://madewithwebassembly.com/all-projects
| slver wrote:
| I can't wait for this fad to be over.
| johnnycerberus wrote:
| Isn't this what the JVM already does?
| lxgr wrote:
| As far as I understand, Hotspot is such an excellent VM
| arhat some languages have been adapted for it as a
| compilation/execution target; it's not particularly well
| suited for running other languages. Especially dynamic
| languages have been struggling with inefficiencies
| imposed by some of the Java-orientied paradigms.
|
| WASM does not provide a garbage collector, as another
| example; this probably makes non-garbage-collected
| languages behave more predictably.
| kaba0 wrote:
| > Especially dynamic languages have been struggling with
| inefficiencies imposed by some of the Java-orientied
| paradigms.
|
| I don't think it is anywhere close to the truth. They are
| very well suited, as the JIT compiler can specialize
| dynamic types (and optionally deoptimize them when the
| type changes). There are also clojure, jruby, a python
| implementation, and java can also be written with
| significant use of reflection.
|
| And then there is GraalVM built on top of the JVM that
| has truffleruby, the fastest Ruby implementation, graaljs
| which has very comparable performance to v8 with
| comparatively much less man hours , etc, all very dynamic
| languages.
| lxgr wrote:
| Was that true even before `invokedynamic`, which as far
| as I know was specifically added to make these non-Java
| languages easier to port and more performant?
|
| All of the examples you've mentioned don't seem like
| trivial ports at least from an outsider's point of view.
|
| The JVM itself has definitely adapted to these use cases,
| but it wasn't designed with them in mind.
| kaba0 wrote:
| You are right about the reason invokedynamic was added,
| but as far as I know the JVM always supported dynamic
| class loading (and thus class creation as well), so while
| not necessarily in a too performant manner, it could
| always be used as a runtime for even very dynamic
| languages. (And I think I left out Groovy which is a
| quite old dynamic language on the JVM).
| pjmlp wrote:
| Yeah, by those that forgot to read their history books.
| lxgr wrote:
| If you're talking about iOS, if you can run WASM, you can run
| JITted JavaScript.
|
| I highly doubt that it's possible to beat the performance of
| JavaScriptCode (in JIT mode) with any WASM-based
| implementation.
| wffurr wrote:
| Depends on whether your JS is limited by interpreter / JIT
| startup time or throughput. If it's the former, then the
| wasm module with wizer might be significantly faster.
| [deleted]
| syrusakbary wrote:
| Not necessarily. WebAssembly can also be run standalone on the
| server-side (without JS).
|
| There are multiple runtimes that allow running Wasm without
| requiring a whole JS engine (Wasmer, WAVM, wasm3, ...)
| jonny_eh wrote:
| That's the missing context, thanks!
| the_duke wrote:
| Not at all.
|
| Webassembly is getting a lot of adoption in non-browser
| environments. Be it extensions for larger applications (like
| Envoy) or "serverless" style microservice or server
| deployments.
|
| There already are plenty of stand-alone WASM implementations .
| (wasmtime, wasmer, wasm3, SSVM, ...)
| jitl wrote:
| One reason to use WASM to run JS, even in a browser, is to
| allow for interruptible execution of untrusted JS code. I built
| a library for this (1.2mb) that uses Emscripten to build
| QuickJS to WASM. I know of a company using my library to
| implement "plugin"/user-scripting using my library.
|
| https://github.com/justjake/quickjs-emscripten#quickjs-emscr...
| hsbauauvhabzb wrote:
| As someone who will shortly need to do two very compute intensive
| functions in the browser (filtering large datasets (100k+ rows)
| via client specified queries, and parsing large sting blobs) what
| is my best option?
|
| I'm aware of server side rendering but I suspect the performance
| in the client may be better responsiveness, with a failover to
| the server if it's faster to provide a query response, but is
| there anything I should _really_ consider for client JS
| performance at that level?
| fabrice_d wrote:
| Since they are working with SpiderMonkey (Firefox JS engine), I
| wonder if that opens the door to a Gecko based browser on iOS
| with decent enough performance. That would be a game changer!
| MaxBarraclough wrote:
| No, that's forbidden by the App Store rules, with a possible
| exception where the HTML is supplied by the app itself rather
| than being downloaded. [0] From Section 2.5.6:
|
| > _Apps that browse the web must use the appropriate WebKit
| framework and WebKit Javascript._
|
| Also Section 4.7:
|
| > _only uses capabilities available in a standard WebKit view
| (e.g. it must open and run natively in Safari without
| modifications or additional software)_
|
| [0] https://developer.apple.com/app-store/review/guidelines/
| sojuz151 wrote:
| You could create a website where you could browse the
| internet with a browser written in JS. No apple approval
| needed.
| maxmcd wrote:
| I think the wasm runtime wouldn't have access to system UI
| primitives. Or would you use the rendering engine to render
| in canvas?
| willio58 wrote:
| They could make it a full blown web app too. App icon,
| notifications, etc.
| oscargrouch wrote:
| This is like a car company that also have a tire company,
| also providing the tires. So far so good, but the company
| that makes the car only allow you to use its own tire brand,
| no others are allowed.
|
| How legislators can easily spot problems in bad company
| practices that forces monopoly in material objects but are so
| obnoxious to everything digital?
|
| I see even tech veterans here struggling in seeing that
| there's a big problem in all this..
|
| Its like Microsoft not only shipping IE with windows, but
| making web sites slow in other browsers on purpose so at
| least in Windows nobody would use the IE competitors.
|
| Why Apple is getting away for more than 10 years to such
| shady practices is beyond comprehension.
|
| And this is just one of them.
| pjmlp wrote:
| Market share, that is how.
| lyptt wrote:
| I find it interesting they compiled SpiderMonkey to WASM to run
| JS in its interpreter mode when it already has iOS support built-
| in via the interpreter. I would've thought all of the performance
| enhancements could be done without involving WASM at all. As far
| as I'm aware the only reason why Firefox for iOS doesn't use
| SpiderMonkey is App Store restrictions.
| wffurr wrote:
| The wizer approach to reducing JS interpreter startup time
| can't work with the iOS built-in interpreter.
| syrusakbary wrote:
| It should probably be named "Making JavaScript to startup fast on
| WebAssembly", since the runtime speed is not really improved by
| their approach.
|
| Besides that, I think Wizer [1] is both an elegant and a simple
| solution to speed up startup times with Wasm. So good work on
| that!
|
| [1] - https://github.com/bytecodealliance/wizer
| neonate wrote:
| https://archive.is/CHqkM
|
| https://web.archive.org/web/20210602191646/https://bytecodea...
| xkyf wrote:
| Run quickly*
| rektide wrote:
| I'm mostly overwhelmed by excitement & fascination. An amazing
| effort.
|
| Three little notes jump out at me, first:
|
| > WebAssembly doesn't allow you to dynamically generate new
| machine code and run it from within pure Wasm code.
|
| This is a surprise to me. For some reason I thought wasm code
| could be a SharedArrayBuffer. And I thought that would be
| mutable. You might maybe have to round trip back to JS to modify
| this? But I thought it was read-write. I'm probably wrong but
| this was quite a surprise to me & a bit of a shocker to hear!
| Although there's good security things you get from this, I didn't
| expect it to be hard set.
|
| Second thing that jumps out at me is a little fear. I look at the
| various projects out there intent on replacing the common
| DevTools debuggable/extension-able web page with a bunch of
| animated pixels, via use of Canvas, like Google's CanvasKit
| renderer for Flutter. To me, this is scary territory, because it
| de-empowers the user. This project here has uses far beyond the
| web, that's it's real purpose I think (who wants to load the
| spidermonkey engine compiled to wasm to start running their js on
| their site), but it still just makes me a little scared of the
| common DevTools experience fracturing & shattering, into many
| pieces. This project isn't uniquely scary, versus Go on WASM, or
| Rust on WASM, but it's still something I'm nervous about, and
| this article made me think of how easy it would be to start
| making the JS we run considerably harder to wrangle by people
| writing extensions or enhancing their user agent.
|
| Third,
|
| > Because the JS engines used to create isolates are large
| codebases, containing lots of low-level code doing ultra-
| complicated optimizations, it's easy for bugs to be introduced
| that allow attackers to escape the VM and get access to the
| system the VM is running on.
|
| Color me a little skeptical about the virtue of adding another
| security layer into the virtual machine. I really hope we can get
| good at isolates, to build blisteringly fast systems, and that we
| don't need to have multiple (or sometimes 1) processes on a
| computer, each running multiple isolates, each running multiple
| wasm containers. It's a cool capability, but I feel like ideally
| we'd be better off with less levels of nesting to get down to the
| real "process" (process->isolate->wasm-container), & better able
| to trust & leverage & use isolates really well to sandbox work.
| It seems to be working very very well for those with neat edge
| tech like CloudFlare Workers.
|
| That said, I just did a quick search & a year ago someone was
| saying V8 isolates take ~3MB of memory each, which is far from
| insignificant. Developing AOT js->wasm tech could potentially
| have a huge memory-saving benefit. Ah, ok, good, the lightweight
| nature of wizer'ed containers is emphasized fairly well in this
| post! It didn't leap out at me the first time but it's definitely
| there! This is the core possible advantage, besides simply
| enabling better exploration of the problem space, which is also
| key.
|
| Fourth,
|
| > We started with making initialization fast with a tool called
| Wizer. I'm going to explain how, but for those who are impatient,
| here's the speed up we see when running a very simple JS app.
|
| This is a huge focus of this post, and it's a great technical
| marvel. On the other hand, the post talks about the advantages of
| how Wizer can use snapshots to skip initialization & start with a
| pre-booted application... the thing is: v8 Isolates can do that
| too. Deno has been doing quite a lot of work figuring out how to
| wrangle & manage & make effective use of V8 Isolates snapshots,
| for example, and that's one of the core reasons I think it is an
| impressively promising advancement & upcoming core technology.
| Deno is really trying to wrap & better expose the V8 runtime in a
| better managed fashion, and I think we'll see many of the
| advantages claimed by Wizer start to get reported out the world
| via Deno as well, over time.
| mamcx wrote:
| > WebAssembly doesn't allow you to dynamically generate new
| machine code and run it from within pure Wasm code.
|
| I think this focus is about RUNNING the wasm. If you have are a
| host, I think you can generate wasm inside it and pre-cache the
| "std library" or something, this is what I infer from this idea
| (from other users that wanna implement it).
|
| Because certainly you can generate code with control of your
| host:
|
| https://docs.rs/wasmer/1.0.2/wasmer/
| kodablah wrote:
| > For some reason I thought wasm code could be a
| SharedArrayBuffer. And I thought that would be mutable.
|
| No, this was an explicit design decision for security reasons.
| Data is mutable, but you cannot exec it.
|
| > You might maybe have to round trip back to JS to modify this?
|
| Yes, this is technically possible but you're unlikely to see
| savings. I'd suspect a "JIT" that instantiates a WASM via the
| JS API using generated bytes from another WASM call won't help
| much (the "exports" would have to be JS calls too or you'd have
| to re-instantiate all the WASMs together to link exports).
| [deleted]
| nielsbot wrote:
| Reminds of Omega--you wrote scripts to operate autonomous tanks,
| and pitted your tanks against others' in an obstacle-filled
| arena. Omega didn't have the realtime scripting component though.
|
| https://en.wikipedia.org/wiki/Omega_(video_game)
| richdougherty wrote:
| Here's the talk related to the article:
| https://www.youtube.com/watch?v=C6pcWRpHWG0
|
| > Nick Fitzgerald -- Hit the Ground Running: Wasm Snapshots for
| Fast Startup > > Don't make your users wait while your Wasm
| module initializes itself! Wizer instantiates your WebAssembly
| module, executes its initialization functions, and then snapshots
| the initialized state out into a new, pre-initialized WebAssembly
| module. Now you can use this new module to hit the ground
| running, without waiting for any of that first-time
| initialization code to complete. This talk will cover the design
| and implementation of Wizer; discuss its performance
| characteristics and the scenarios in which it excels and when it
| isn't the right tool; and finally, in the process of doing all
| that, we'll take a closer look at what makes up the guts of a
| WebAssembly module: memories, globals, tables, etc.
|
| Lots of interesting talks at the recent WebAssembly Summit!
| https://2021.webassembly-summit.org/
| chrisseaton wrote:
| Sounds a lot like how GraalVM runs Java applications to the
| point where they're initialised and then compiles them to
| native code.
| mamcx wrote:
| This sound tempting.. I'm building an interpreter
| (https://tablam.org) ad one of the reason is the interpreters are
| better for exploration/repls and such.
|
| This looks like it will fix a major point: I could compile
| everything that is typed and left the rest for runtime.
|
| I'm wondering how much easier could be the life if I compile to
| WASM to be run on my host...
___________________________________________________________________
(page generated 2021-06-02 23:00 UTC)