
Compiling Quake 3 Virtual Machines To JavaScript - mariuz
http://www.inolen.com/articles/compiling-quake-3-virtual-machines-to-javascript/
======
jevinskie
It would be cool if it compiled either LCC assembly or QVM bytecode to LLVM
IR. Now you have all of LLVM's optimizations! Finally, spit out the JS using
Emscripten like the rest of the project.

~~~
ris
I thought that too, but remember this has to all be done at runtime, so
depending on LLVM would require an Emscripten-ized version of LLVM (does such
a thing exist?) to be distributed with the generated js and similarly
depending on Emscripten would require a copy of Emscripten to be distributed
with the generated js. And from what I hear the runtime performance of
Emscripten itself ain't that great.

~~~
derefr
Why does this have to be done at runtime, exactly? How many mods (or rather,
QVM files) were there? And are people still making them?

If the answer is "less than 100K" and "no, of course not," then you can
probably get away with:

1\. compiling all the QVM files to their Javascript equivalents ahead-of-time;

2\. stuffing them all on a CDN (with each JS blob named after the md5 of the
relevant QVM source);

and then 3. having a "compiler" in your client that just hashes the source
it's about to "compile", and requests the blob with that hash from your CDN.

Of course, if the amount of generated JS is small _enough_ , you could even
just serve it all with the client. I'm doubting that one, though; it's
probably at _least_ 50MB of code. (Though it might be heavily _redundant_
code... it could compress very well!)

~~~
ris
> Why does this have to be done at runtime, exactly?

Because that's how quake3 works. What you're describing would be incompatible
with all other quake3 clients. And part of the point of implementing the QVM
in the first place is compatibility.

------
ItendToDisagree
This is pretty crazy impressive! The performance gain particularly. Is that
much of a gain expected?

~~~
ori_b
I'm impressed, but I'm not particularly surprised. The initial code was
interpreted, while the new code is JIT compiled. I have no data to back this
up, but I suspect that if instead of generating javascript, he generated x86
assembly, you'd see a similar speedup. Possibly a larger one.

~~~
Scaevolus
That's exactly what Quake3 did natively, and it gave a large performance
boost.

~~~
inolen1
Right. Pulling from JC's August 16, 1999 .plan
([http://floodyberry.com/carmack/johnc_plan_1999.html#d1999081...](http://floodyberry.com/carmack/johnc_plan_1999.html#d19990816))
when he first wrote the x86 compiler:

Q3demo1 dll: 52.9 Compiled: 50.2 Interpreted: 43.9

Q3demo2 dll: 50.1 Compiled: 46.5 Interpreted: 38.7

------
webbedhands
What is up with that comment?

~~~
sho_hn
It's the guy writing TempleOS. Google around, you're in for an interesting
story.

~~~
itry
Does he have a new hn account? I love to read his stuff. But the account
"losethos" has been inactive for over a month now.

~~~
uptown
Here's your primer:

[https://twitter.com/losethos](https://twitter.com/losethos)

[http://www.templeos.org/](http://www.templeos.org/)

------
cgdangelo
Very nice. Glad to see CPMA in there. :-)

------
_random_
'Transpiling' since it kind of converts to a scripting language not a native
code.

~~~
pacala
asm.js is portable assembly with a jit assembler. In that sense, it's even
closer to "native code" than C, as C requires a separate compilation step.

~~~
eliasmacpherson
I am confused, there are JIT compilers for C:

[http://code.google.com/p/asmjit/](http://code.google.com/p/asmjit/)

[http://homepage1.nifty.com/herumi/soft/xbyak_e.html](http://homepage1.nifty.com/herumi/soft/xbyak_e.html)

How is asm.js different to those?

~~~
pacala
Embedding jit assemblers into C binaries is different than jit-ing the C
language itself.

~~~
eliasmacpherson
So is asm.js not run from a binary, that compiles the js JIT? C JIT compilers
compile C code JIT, I still don't see the difference.

The two projects I linked to were incorrect, they are for interpreting asm
JIT.

What I meant to point to were:

[http://root.cern.ch/drupal/content/cling](http://root.cern.ch/drupal/content/cling)

[https://metacpan.org/pod/C::TinyCompiler](https://metacpan.org/pod/C::TinyCompiler)

~~~
pacala
Thanks for the pointers. Looks like asm.js and C are on par as portable
assembly targets. The one difference is that asm.js is ready to use by half a
billion users, the other is that no sane human should code asm.js directly,
whereas some people swear by C as a language for humans. Allow me to clarify
the initial statement:

> For 99.9% of the end users, asm.js it's even closer to "portable native
> code" than C, as C is usually delivered to end users as a precompiled binary
> via a separate compilation step, therefore no longer portable.

~~~
eliasmacpherson
The reason people call C portable assembly is because it's about as low as you
can go without coding in assembly, and still have it compile to various
platforms.

You are really comparing asm.js and C as portable assembly emitters rather
than targets. That said, people very occasionally use C as a target like they
use asm.js, e.g. the original C++ compilers, the mars rover.

asm.js is as low as you can seemingly go and have it run in a modern version
of Chrome and Firefox, but those requirements prevent it from being a portable
assembler in the sense that C is. In addition, it's sensible to write your
program in another language first before asm.js, as I understand it.

There's a whole swathe of machines (rather than users) out there that cannot
run a modern version of those browsers, i.e. asm.js is not portable to them.

When the code being written in and transposed from is asm.js and the
destination is some other language - then asm.js will be portable assembler in
the sense that C is.

