asm.js in Firefox Nightly

I’m happy to announce that OdinMonkey, an asm.js optimization module for Firefox’s JavaScript engine, is now in Nightly builds and will ship with Firefox 22 in June.

What is asm.js? Why are we doing it, and how are we getting to within 2x of native performance? This post won’t be able to go into too much detail since we’re hard at work preparing for Mozilla’s upcoming GDC session, which you should definitely come see (Wednesday 11am, Room 3024, West Hall). After GDC, expect full coverage of these topics by Alon, Dave, myself and surely others. For now, allow me to point you at the asm.js FAQ, Alon’s mloc.js slides, a nice Badass JavaScript post and a more in-depth post by Axel Rauschmayer.

Want to see it in action? Download a new Firefox Nightly build and try out BananaBench. (Note: BananaBench runs with a fixed time step to make JS execution deterministic, so game speed will run fast/slow, depending on your hardware/browser.) Or, check out a demo of the Emscripten-compiled Bullet engine simulating a ton of falling boxes.

At the moment, we have x86/x64 support on desktop Windows/Mac/Linux and support for mobile Firefox on ARM is almost done. Since we intend to continue to iterate on the asm.js spec in cooperation with other JS engines, we’ve put OdinMonkey behind the flag javascript.options.asmjs in about:config. This flag is currently enabled by default on Nightly and Aurora, and if nothing changes over the next 12 weeks, will be automatically disabled in Beta and Release. By then, we hope to be happy with a stable “asm.js v.1″, we’ll enable it everywhere and ship with it enabled in our final builds. [Update: OdinMonkey has been enabled by default for all releases starting with Firefox 22.]

If you want to start experimenting with asm.js right now, you can:

  • Get Emscripten and start compiling C/C++ code. (Don’t forget the -O2 -s ASM_JS=1.)
  • Check out the draft spec and start writing asm.js by hand.

In the future, we’d like to see a rich third option of generating asm.js using a more ergonomic front-end language (e.g., a derivative of LLJS). [Update: LLJS work is already underway!]

How do you know if you are generating valid asm.js and taking full advantage of OdinMonkey? In the old days, this was a frustrating question for developers. Maybe you were doing something wrong, maybe the code, as written, was just slow. One cool thing about asm.js is that the "use asm" directive makes the programmer’s intention quite clear: they want to compile asm.js. Thus, if there is an asm.js validation error, OdinMonkey will print a warning on the JavaScript console. (OdinMonkey emits a warning, instead of throwing an error, since asm.js is just JavaScript and thus cannot change JavaScript semantics.) In fact, since silence is ambiguous, OdinMonkey also prints a message on successful compilation of asm.js. (There is currently a bug preventing asm.js optimization and warnings in Scratchpad and the Web Console, so for now experiment in regular content.)

For those who are itching to do some performance experiments: go for it, we’ve been pretty happy with the results so far when asm.js is applied to new codes, but we’ve also seen plenty of cases where the C++ compiler is doing important backend optimizations that we haven’t taught our IonMonkey backend yet. We expect continuous incremental improvement as we measure and implement new optimizations to close this gap. Second: one performance fault that we already know trips up people trying to benchmark asm.js is that calling from non-asm.js into asm.js and vice versa is much slower than normal calls due to general-purpose enter/exit routines. We plan to fix this in the next few months but, in the meantime, for benchmarking purposes, try to keep the whole computation happening inside a single asm.js module, not calling in and out.

In closing, I leave you with the musical inspiration for OdinMonkey:

Happy hacking!

50 Responses to asm.js in Firefox Nightly

  1. Pingback: Firefox Nightly Now Includes OdinMonkey, Brings JavaScript Performance Closer To Running At Native Speeds | TechCrunch

  2. THIS. IS. FREAKING. AWESOME.

    Both after seeing your Muse I am not suprised anymore :D

  3. Congratulations, this is great news! And thanks for recognizing that silence is ambiguous :)

  4. This can give a second life to the JS backend of PyPy

  5. Does asm compiled code run slower than it’s non-asm counterpart when running in JS engines without asm.js optimization modules? Or can it run at all?

    “…we’ve also seen plenty of cases where the C++ compiler is doing important backend optimizations that we haven’t taught our IonMonkey backend yet. We expect continuous incremental improvement as we measure and implement new optimizations to close this gap.”

    Will these new optimizations also help normal JS JITing or will they only help the asm.js module? (If so that means the asm.js project is actually helping to zero in on inefficiencies/optimizations in ionmonkey which is stinking awesome!)

    • Does asm compiled code run slower than it’s non-asm counterpart when running in JS engines without asm.js optimization modules?

      asm.js-compilation generally doesn’t affect performance too much on non-asm.js-optimizing engines. In some cases, we’ve observed big speedups on Chrome/Firefox on asm.js, presumably because the rigor of asm.js’s type system forced Emscripten to add a coercion that was previously missing and necessary for good codegen.

      Will these new optimizations also help normal JS JITing or will they only help the asm.js module?

      Since OdinMonkey reuses the same IonMonkey backend as normal JITs, you’re right, it will help normal JITing.

      (If so that means the asm.js project is actually helping to zero in on inefficiencies/optimizations in ionmonkey which is stinking awesome!)

      Absolutely! We have a tentative plan to instrument C++ when compiled to native and asm.js so that we can compare the two and see on which basic blocks we are spending disproportionately more cycles and, from there, zoom in on the important optimizations.

      • asm.js is still exciting, but this dynamic is as, or more, exciting to me because it will help speed up our JIT for everyone, not just asm.js users.
        I wonder if the Chrome folks do something similar to help teach their JIT optimizations?

        • In it’s current form, asm.js is specialized for compiled C++ code: asm.js code cannot manipulate objects/strings directly, only integers and doubles. That limits the ability to convert large swaths of JS to asm.js in any automatic way, since we’d effectively have to write a JS VM in asm.js (inception!) which would be slower than running JS directly in the browser. Don’t worry, full JS will continue to keep getting faster as browser JS engines compete, improve and learn from each other.

          • Understood, and thanks for your answers.
            I was just wondering (in my comment down below) if there might be places in Firefox code that we use normal JS that it might make sense to convert to asm.js?
            If so, that might make a good snappy project (find places that could be converted).

            • There might be and it’d be worth looking. My guess, though, is that we might have a hard time finding good candidates: if a piece of Firefox frontend JS was hot enough to matter and amenable to asm.js, I’d expect that we would have already moved it into C++ that gets called by frontend JS.

              • Ahh, yes, I understand.
                I might wonder then if FxOS would be a better candidate for a survey as we’re much more limited from integrating C++ in our shipping apps (if I understand correctly).

  6. Awesome work, I look forward to testing it out!

  7. Simply amazing work. Keep it up!

  8. Two questions: How do I debug such generated javascript code? Normal chrome debugger works, is it readable?

    And how big is the resulting javascript? There is no point in using this if every script I generate towards asm.js has a 50kb overhead. (personally even 25kb would be stretching it for me, but I’m anal about that)

    • Two questions: How do I debug such generated javascript code? Normal chrome debugger works, is it readable?

      At the moment, turning on the debugger disables asm.js optimization (so the baseline JIT will be used). We plan to support debugging asm.js in the future. If the asm.js code has been minified it is pretty difficult to understand. However, before minification, it’s fairly readable once you understand the basic asm.js rules for loads/stores.

      And how big is the resulting javascript?

      gzipped minified asm.js is pretty comparable to gzipped binaries. See Alon Zakai’s post on this.

  9. I came for the song, asm.js was a great bonus :)

  10. Wow again , that’s the success of open technology ! well done guys ! i love it

  11. As a side note, wouldn’t it make sense – once this has been well proven in a stable release form – to convert as much Firefox code (desktop, Android, FxOS & its shipping apps) to asm.js as possible?
    I am not a developer and admit to not fully understanding what’s going on – perhaps there isn’t much code that can be formatted in this manner, or there isn’t enough of a net benefit. But if so, man, we could help to speed up everyone’s experience.
    Also, would it be possible to automate converting current JS into asm JS? If that were possible not only could web developers the world over use it, but we could run it on Firefox’s code pre-compile time.
    If it’s not possible to automatically convert normal JS, perhaps we could create tools to make it easier?

  12. Pingback: Crazy Fast JavaScript Hits Firefox Nightly (With A Few Conditions) | Lifehacker Australia

  13. T-shirts or it didn’t happen. :)
    D

  14. Excellent news! Do you have any plans to support other languages except C / C++? In some case C is too low level, but we still want to use new asm.js features.

    • I’m not Luke, but you might gain some more insight to your question by looking through the slide deck link on http://asmjs.org/

    • The glue between C/C++ and asm.js is emscripten. From emscripten on github (emphasis added):

      Emscripten is an LLVM-to-JavaScript compiler. It takes LLVM bitcode – which can be generated from C/C++, using llvm-gcc or clang, or any other language that can be converted into LLVM – and compiles that into JavaScript

      So if some other language has an LLVM compiler then you can run its output through emscripten. Otherwise, someone has to write a compiler for it that outputs JavaScript, and if appropriate use the asm.js subset of JavaScript in its generated code. Here’s a huge list of languages that already compile to JS.

  15. Where is asmjs mailing list for comments on the draft spec and questions etc

  16. Pingback: Firefox OdinMonkey and Native Assembly JavaScript, High-speed Java Monkey Business in the Battle of the Browsers… | Highpants

  17. For closer to 1:1 to C performance, are there any plans to use LLVM as a backend generator for Asm.JS code (on desktop machines)!? I know that LLVM will increase even more the compilation time, but it should also bring visible speedups.

    Thank you for the great work you did with Asm.JS! I am using Nightly just because of it! ;)

    • LLVM is definitely a possibility, but it has a pretty high cost in Firefox download size, asm.js compile time, and engineering. For now, we’re going to see how far we can push the IonMonkey backend since it benefits all JS.

  18. Nice ! I’m trying this in Aurora 22, and there is a small ambiguity : “[13:42:31,989] Error: Successfully compiled asm.js code”, the hole being a warning :-)

    Anyway, that’s pretty awesome !

    • Note : That was on BananaBench, but no “Error” on the falling boxes demo.

    • Yes, that is an aesthetic bug we’ve been meaning to fix: we need to add a new “Info” classification of JS engine diagnostics. Rest assured, though, that is the message that says everything is working :)

  19. From the talk (http://kripken.github.io/mloc_emscripten_talk/), we could see quite a lot of performance data on both micro and macro. I wonder whether those micro and macro are available to download. I only find bullet on this log. What about the skinning, zlib and all the micros (copy, corrections, primes etc). Thanks~

  20. Hi Luke,

    I’ve been hand-coding some vector-calculation test cases to try to get some idea of what kind of stuff is ripe for asm.js optimisation, but in most cases my straight javascript implementations win by a fair margin (using Nightly 3013-05-05). I noticed early on that calling in to an asm.js “module” is pretty slow, so instead I’ve been using large iterations of calculations inside the functions.

    So I guess I’m asking whether there exists any simplified reference / example code that demonstrates some performance gains so I can start developing some intuition about what works and what doesn’t?

    • I noticed early on that calling in to an asm.js “module” is pretty slow, so instead I’ve been using large iterations of calculations inside the functions.

      Yes, that’s what I was trying to warn about in the last major paragraph of the post :) We will be optimizing this soon (asm.js to non-asm.js calls are close).

      So I guess I’m asking whether there exists any simplified reference / example code that demonstrates some performance gains so I can start developing some intuition about what works and what doesn’t?

      See “Running Emscripten Test Suite and Benchmarks” for some small examples. In general, the call path into and out of asm.js is the only thing to watch out for. Also, OdinMonkey assumes the compiler has done inlining already and so OdinMonkey doesn’t do any inlining itself.

  21. Pingback: CyanogenMod 10.1 Release Candidate Rolls Out For The Sony Xperia Tablet Z [Update: Nighlies Too] | Toki Solutions

  22. Pingback: Mozilla Firefox 22 | Just Now Tech

  23. Pingback: Mozilla Firefox Updates to Version 22 | PHP World

  24. Pingback: Mozilla Released Firefox 22, enables Super-Fast Javascript and WebRTC - Techaddy

  25. Marc Nieper-Wißkirchen

    I am currently doing some experimenting with asm.js by writing a little compiler for a scheme-like language. I am wondering how much I have to benchmark asm.js to let the compiler backend output optimal asm.js code or whether it is planned that OdinMonkey does its own optimizations (e.g. inlining of functions, loop unrolling, reordering code) when compiling the asm.js code to native code.

    (Of course, it would be very nice if asm.js was compiled by optimizing compilers because if I tried to optimize my generated code by hand for one compiler, it might not be the best code for a different compiler. Further, asm.js has to be restricted to remain proper JavaScript, so some things might be faster (or more direct) to implement natively on the CPU than in asm.js, and only the asm.js compiler has access to the native CPU.)

    • At the moment, asm.js compilation with OdinMonkey doesn’t do any function inlining, unrolling, or tail-calling optimizations. The reasoning is that we expect this to have been done already by the compiler and so any inlinining the JIT backend performs would add monitoring overhead, compilation pauses during gameplay when we decide to recompile (one of the goals of AOT is to avoid unpredictable pauses), or, in the worst case, introduce pathological behavior (when we make bad inlining decisions). We could also make inlining decisions AOT, but now we have no more information to make inlining heuristic decisions than Emscripten. One can imagine various conservative heuristics/strategies that could avoid these problems, though, and maybe we’ll pursue some of them in the future.

      • Marc Nieper-Wißkirchen

        As ECMAScript doesn’t have a goto statement, asm.js doesn’t have either, of course. However, being a compilation target such a statement and even a computed goto as in gcc would be quite handy (think of an interpreter loop or a trampoline).

        The way to (at least partially) emulate this is of course a huge switch statement wrapped inside a forever running while loop, where a variable, say l, holds the current label. For a simple goto, the corresponding asm.js code would be l = ; continue loop; for a computed goto, the code would be l = ; continue loop.

        A general compilation of this while/switch construct into machine language wouldn’t yield very efficient code (I guess, this is why Emscripten needs all this relooping). Therefore, it would be nice if the asm.js spec (or OdinMonkey) defined a convention of coding such a while/switch construct such that OdinMonkey is able to recognize such a structure and compiles the goto workarounds into direct and indirect jumps in machine code.

        Should I file a bug for this feature request? Or is there a better place to post such a suggestion?

        • That’s a great point and one I really wanted to do when we were starting. At the moment, relooping seems to mitigate the problem enough that it hasn’t been necessary, but one can imagine cases where relooping is inconvenient (a JS JIT written in JS) or where the relooping algorithm breaks down (irreducible code). In those cases, yes, I think we would want what you are talking about. Filing a bug on the asm.js github page is probably the right place.

  26. Pingback: Mozilla in 2013 | Mozilla Press Center

  27. Pingback: Mozilla in 2013 Firefox Mobile OS Download

  28. Pingback: Mozilla muy activa en el 2013 | Universotek

  29. Pingback: GDC 2014: Mozilla and Partners Prove the Web is the Platform for Gaming | The Mozilla Blog

  30. Pingback: GDC 2014: Mozilla and Partners Prove the Web is the Platform for Gaming | Mozilla Press Center

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>