This seems very much targeted at emscripten and not to cross-compilers that start with GC'ed languages like GWT, Dart, ClojureScript, et al. If you are cross-compiling Java or C# to asm.js, you don't really want to manage memory manually. I work on GWT, and asm.js as an output target is very interesting to me (I've worked on a number of performance Web games using it, GwtQuake, AngryBirds, etc), but the starting assumption is GC, so I want to leverage non-boxed numerics, and all of the other nice stuff, but don't want to stuff everything into a TypedArray.
It's also unclear to me how this solves the problem of startup time on mobile. A giant glob of Javascript takes a non-trivial amount of time to load even on today's fastest smartphones. The spec seems to argue that Browser VMs could recognize asm.js and if I read between the lines, employ snapshoting the app and caching it for later quick startup?
In all likelihood, the majority of asm.js outputs would be actually be non-human readable output of optimizing cross-compilers, so there isn't much benefit from having a readable syntax that humans could read, so what's the real justification for using JS as an intermediate representation over say, a syntax specifically designed for minimum network overhead and maximum startup speed? Seems like it might be worthwhile for Mozilla to also work on efficient representations of asm.js that minimize this overhead. The usual response is minify + gzip, but it's not a panacea.
First of all, we do care very much about supporting compilers for managed languages like Java and C#, but we're starting with this first version that only supports zero GC and atomic primitive types. We have plans to grow outwards from there to support structured binary data, based on the ES6 binary data API, and controlled interaction with the GC. Luke has ideas about how to do this without losing the predictable performance for lower-level compilers like Emscripten.
We do have plans for startup time. I hope to pitch a very small, simple API for a kind of opaque compiled Function. Internally we've been calling it FunctionBlob (we'll bikeshed the name later). The idea is that `new FunctionBlob(src)` is almost identical to `new Function(src)` except the object is (a) an opaque wrapper that can be converted to a function via `fblob.toFunction()` and (b) entirely stateless and therefore compatible for transfer between Workers as well as offline storage. This would essentially make it possible to do things like background compilation of asm.js on a Worker thread, and caching of the results of compilation in offline storage. That way next time you startup you don't have to download or optimize the source. (This could work especially well with the app experience where you could perform these download/optimize steps as part of the installation process.)
As for the use of JS, this is purely pragmatic. The code works today in browsers, so people can start using it and it works -- and even quite fast; Emscripten is already shockingly performant in Firefox and Chrome -- but over time it'll see better and better optimization.
Presumably, if it was a blob, it could also be stored in local storage/indexdb/filesystem API? Is the internal format supposed to be architecture neutral, or dependent? I can see arguments for either, but if it were neutral, than the blob conversion could be done offline/statically on the server, and downloaded by the client dynamically (e.g. XHR to fetch function blobs). If it were architecture dependent, then I could see advantages as well, letting the browser vendor choose the optimal form of the blob. This would potentially yield better performance, but you wouldn't be able to host blobs on the server.
I was only thinking that it would be internal. Your server point is good, but I think way, way harder, and kind of starts the whole project back at the beginning: how to design a standard, efficient, optimized bytecode format. So I think it's probably not really feasible.
Not the same, but an additional optimization you can do is incremental compilation. Because you have JavaScript's eval, you can download the code a bit at a time and optimize (and cache via FunctionBlob) each piece.
Storing it and transferring it on the server is one thing; serializing it locally in the browser itself might be a more reasonable goal? That is, it wouldn't be expected to be portable to anything but that very same browser, but it would allow you to cache the compiled result. (I would expect the serialized string to be signed by the browser itself, to prove that it was created by the browser – and for the deserialization to fail on some browser upgrades).
Care would have to be taken to ensure that these blobs cannot be mutated via other means, or that a non-function blob can be converted to a function blob with passing through validation, otherwise it might be an attack vector, for someone to figure out the internal representation, and manipulate storage to forge one that trips up some fast-path code which makes assumptions about the input being correct.
Right, that's the idea of FunctionBlob. It wraps a browser-internal representation of the optimized compiled code. The web code can instruct the browser to store that offline, without exposing its implementation-specific details to the web code. The web code can then, in a later session, retrieve that optimized code from storage as another FunctionBlob, which it can then convert into a Function. This is no different from just storing the asm.js source code in offline storage, except it avoids redoing the work of compiling and optimizing the source. (It'd still have to be stored in position-independent format and there might be some back-patching necessary when reloading it.)
I think GC interaction should be the highest priority. As a way to run C/C++ in the browser at native speed, asm.js is awesome, but as a way to run Python, Java, Go, etc in the browser at native speed, asm.js would be world-changing.
Very cool. My position for years has been that "Javascript is the defacto bytecode of the web" is, on balance a very good thing. However, it has been a bit of a hack.
What you're proposing is: "Javascript is the bytecode of the web/ How about we make it a much better bytecode?"
"I work on GWT, and asm.js as an output target is very interesting to me (I've worked on a number of performance Web games using it, GwtQuake, AngryBirds, etc), but the starting assumption is GC, so I want to leverage non-boxed numerics, and all of the other nice stuff, but don't want to stuff everything into a TypedArray."
I'll let dherman elaborate in more detail, but he is working on it. :)
"The spec seems to argue that Browser VMs could recognize asm.js and if I read between the lines, employ snapshoting the app and caching it for later quick startup?"
This is really a problem with any portable code delivery format that wants to run compiled code. You either have to stick to native code, in which case you aren't portable, or you have to compile on the client, which adds startup time. Caching of compiled artifacts is going to be necessary in any portable solution, and I don't see any reason off the top of my head why this would be particularly different for asm.js.
"Seems like it might be worthwhile for Mozilla to also work on efficient representations of asm.js that minimize this overhead. The usual response is minify + gzip, but it's not a panacea."
I agree, and I've talked to Alon about this. I think that it would be an interesting project to develop a format that compresses asm.js down as small as possible. Then you can simply uncompress and eval on the client side to ensure backwards compatibility.
Java went through a similar issue with their pack200 format. I am not privy to where all the time is spend in mobile JS startup (parsing, etc). It seems like using some kind of special JS precompressor would both benefit entropy coding as well as allow a faster parser, but I've seen it turn out to be a wash in the past. :( However, even if you could reduce network bandwidth, it would be a win for people's data plans and batteries. :)
Yes, this has downsides like compiling your own GC. For GC heavy code it might be slow. But for raw computation you would probably get faster results than source-to-source like GWT does - you get LLVM optimizations, and you get asm.js which is easier for JS engines to run quickly.
> It's also unclear to me how this solves the problem of startup time on mobile.
Yeah, that is a problem. It's a problem on normal JS too, and also for things like PNaCl. Only shipping final native binaries can fully avoid that (but that is nonportable).
> The spec seems to argue that Browser VMs could recognize asm.js and if I read between the lines, employ snapshoting the app and caching it for later quick startup?
Yes, that is one possibility. It could work for normal JS too, I'm not sure why it hasn't been done yet. Worth investigating.
> In all likelihood, the majority of asm.js outputs would be actually be non-human readable output of optimizing cross-compilers,
Yes.
> so there isn't much benefit from having a readable syntax that humans could read, so what's the real justification for using JS as an intermediate representation over say, a syntax specifically designed for minimum network overhead and maximum startup speed?
The justification is that asm.js code will work, right now, in all browsers. (And it can fairly easily be optimized by them to run much faster than compiled code in JS.) Any new format would require standardization and take a long time. asm.js is just JS.
For network transmission, we should implement a special minifier for it (written in JS of course).
This needs to be shouted from the rooftops. This is the single most important constraint of the project and also its greatest strength.
So asm.js isn't the magical perfect browser bytecode that everyone on HN wants -- and which would have all manner of flaws if it actually existed in concrete form, rather than a platonic ideal in people's heads -- but that's a completely unrealistic goal anyway.
But asm.js is usable in all browsers immediately. asm.js is just JS.
> But asm.js is usable in all browsers immediately. asm.js is just JS.
A magic JS-based bytecode that's usable in all browsers immediately isn't useful if it isn't fast. Which it isn't, because it's a JS-based bytecode executing under existing JS engines.
So now we have apps that perform incredibly poorly when run on a browser without "asm.js" support, and a rather ridiculous bytecode format that will have to be parsed natively to run reasonably quickly, with a fair bit more complexity for every layer in the development and runtime stack because they insist on keeping it as valid JS syntax.
Our numbers show asm.js can be 2x slower than native or better. That's not "not fast". And, even without asm.js optimizations, the same code is 4x slower than native, which is as good or better than handwriten JS anyhow - which is not "incredibly poorly".
If you have other numbers or results, please share.
For a desktop and/or mobile app, on which the consumer is waiting and you are burning battery (laptop/phone) or just simply CPU cycles, 2x-4x slower is 'not fast'. You're simply wasting the end-users time and resources for what amounts to ideological reasoning.
We're always making a trade-off between performance and ease of programming, but when your competition is coming in at 2x faster than your optimal case, and 4x in the standard case, you're going to lose for all but the simplest apps.
How does PNaCl compare in terms of performance to "native" code? It still has the compilation overhead, it still has a lot of the bounds checking… It's not clear to me that PNaCl will actually be much quicker than asm.js.
I believe the ideal (for users) would be to target NaCL natively, with a fallback to server-side PNaCL compilation, and an absolute fallback to PNaCL compilation/execution.
>Python, for one, is plenty usable, and is not fast.
In any environment where I might currently choose to use Python I also have the option to use something else for parts of the project where Python proves to be too slow. Will FirefoxOS provide such an escape hatch?
>JS engines are close to Java/C in speed
'close' is a pretty vague term. For a lot of tasks Ruby is 'close' enough to C that the difference doesn't matter. For a different set of tasks Java is not 'close' enough to C (or C+asm) to be a viable choice and neither is Javascript.
I'd also like to point out that battery life does matter, and using at least twice the CPU cycles for most tasks isn't conducive to good battery life.
>In any environment where I might currently choose to use Python I also have the option to use something else for parts of the project where Python proves to be too slow. Will FirefoxOS provide such an escape hatch?
Seeing that Python is 10-20 times slower than V8 for most Python/JS native operations, you should have that problem much. Especially considering that the purpose of asm.js is to give you an even greater boost in speed. And seeing that NaCl never got anywhere, not only this is your best bet but it's far better than anything else out there at the moment.
asm.js IS a bytecode format. That it is human readable or that it accepts some tradeoffs because of JS doesn't matter. The end result (after the JIT pass) would not be any slower for it. The only problem with a readable "asm" would be slower load times, but that can be taken care of in the future by providing some pre-compiled format or more control over caching if asm succeeds.
Please be careful with the "close to C in speed" claim.
There are only a very small number of languages that can legitimately claim that (C++, Fortran, and sometimes Ada). Java is not one of them. JavaScript is surely not one of them, even with the latest versions of V8.
The only time we see performance remotely close (which still usually means several times slower, at best) to C is for extremely unrealistic micro-benchmarks that have been very heavily optimized to a state where they don't at all resemble real-world code.
We have had Word Processors and Spreadsheets in Javascript (Google Docs), 3D and 2D games, and even a h264 decoder and a PDF renderer. Heck, they have ported QT to Javascript, and the example applications run at a very acceptable speed. None of the above are slow.
So, no, it's not true that V8 is only fast in selected "microbenchmarks".
You might not do scientific applications or NLE video editing with it, but for everything else it should be just fine.
>'Very acceptable' speed isn't what consumers are looking for when comparing battery life and wall-clock performance between competing platforms.
Where does the idea come that V8s and co very acceptable speeds come at the expense of battery life and wall-clock performance???
Not to mention that people are using far less capable web apps in the mobile and desktop space now (i.e pre-asm.js javascript), so the increase in speed due to the asm.js/optimisation standardisation would only make battery life and wall-clock performance better.
> This seems very much targeted at emscripten and not to cross-compilers that start with GC'ed languages like GWT, Dart, ClojureScript, et al.
That's correct, although one could implement a garbage collector on top of the typedarray heap (we have working examples of this). There are some limitations to GCing the typed array manually, though, such as not taking advantage of the browser's ability to better schedule GCs.
Looking further in the future, though, it would be completely reasonable to extend asm.js to allow the super-optimizable use of the upcoming BinaryData API [1] in the style of JVM/CLR-style objects. Again, though, this is speculative; BinaryData isn't even standardized yet.
> It's also unclear to me how this solves the problem of startup time on mobile.
We have several strategies to improve this. The "use asm" directive, in addition to allowing us to produce useful diagnostic messages to devs when there is an asm.js type error, allows us to confidently attempt eager compilation which can happen on another thread while, e.g., the browser is downloading art assets. Looking farther in the future again, we could make some relatively simple extensions to the set of Transferrable [2] objects that would allow efficient programmer-controlled caching of asm.js code including jit code using the IndexedDB object store.
> In all likelihood, the majority of asm.js outputs would be actually be non-human readable output of optimizing cross-compilers, so there isn't much benefit from having a readable syntax that humans could read, so what's the real justification for using JS as an intermediate representation over say, a syntax specifically designed for minimum network overhead and maximum startup speed?
Before minification, asm.js is fairly readable once you understand the basic patterns, assuming your compiler keeps symbolic names (Emscripten does). The primary benefit is that asm.js runs right now, rather efficiently, in all major browsers. It also poses zero standardization effort (no new semantics) and rather low implementation effort (the asm.js type system can be implemented with a simple recursive traversal on the parse tree the generates IR using the JS VM's existing JIT backend). This increases the chances that other engines will adopt the same optimization scheme. A solution for native performance is only a solution if it is portable and we want to maximize that probability.
> The usual response is minify + gzip, but it's not a panacea.
In addition to minify+gzip, one can also write a decompressor in asm.js that unpacks the larger program. Also, see [3] for how minified gzipped Emscripten code is comparable to gzipped object files.
It's also unclear to me how this solves the problem of startup time on mobile. A giant glob of Javascript takes a non-trivial amount of time to load even on today's fastest smartphones. The spec seems to argue that Browser VMs could recognize asm.js and if I read between the lines, employ snapshoting the app and caching it for later quick startup?
In all likelihood, the majority of asm.js outputs would be actually be non-human readable output of optimizing cross-compilers, so there isn't much benefit from having a readable syntax that humans could read, so what's the real justification for using JS as an intermediate representation over say, a syntax specifically designed for minimum network overhead and maximum startup speed? Seems like it might be worthwhile for Mozilla to also work on efficient representations of asm.js that minimize this overhead. The usual response is minify + gzip, but it's not a panacea.