Lisp System Implementation
t3x.org
t3x.org
I absolutely love the minimalist website design which reminds me of Zork and old terminals.
Why spend the entire book on tokenization circa 1981 when what's really needed are compact, fast, executable machine code binaries?
I can in fact compile with profile collection, both Sun Studio and hp compilers support that for decades. Then I run the representative workload and then recompile while feeding the compiler with the collected data.
I'm not saying that JIT is always better. It seems to me there are cases for that though.
I want machine code executables. No JIT. Not even in the theoretical case where it might be faster long term, first because those cases are practically non-existent: daemons don't usually crunch numbers but JIT versions consume inordinate amounts of memory and second they don't actually provide portability: take any audiovisual demo and try to run it on all the platforms which the VM supports: I want to know how many will play sound and how many will correctly and quickly display graphics.
JIT and VM's are a lie.
Pretty much every modern implementation of every programming language has an intermediate representation -- GCC has one[1], LLVM has several [2,3], and unless you're programming in Forth (which notably generally doesn't have an intermediate representation), you're probably already happy with a language with an intermediate representation of some kind and just don't know enough to appreciate it.
The idea that "compile[d] straight to a machine code executable" is a line in the sand worth squat is just ignorant.
[1]: http://gcc.gnu.org/onlinedocs//gccint/RTL.html
The LISP9 Abstract Machine, which is described in the book, is very close to the metal. So much so that you might as well emit machine code instead. The approach is outlined (but not described in detail, as you noted) in the last chapter.
Then abstract machines have one huge advantage and that is portability. I can just compile the system on x86, ARM, SPARC, MIPS, Alpha, or whatever and it will simply run. So whatever the reader has, the code will work. (I acknowledge that pretty much everybody uses x86 today, but still...)
So... Thank the world for IR, ByteCodes and VMs.
Exactly, thank you!!! So why the hell would you screw around with bytecode!?!?!
I don't want portability, my source code is portability! I want the fastest possible machine code translation for the smallest possible program!!! That "portability" thing with bytecode makes me absolutely livid!!!
Maybe with tools like LLVM it has become a bit less common to do all that on your own, but not everybody wants to use LLVM and spitting out your own machine code directly, without even having a bytecode interpreter, still seems like a rather bad idea. Besides loss of retargetability, the generated machine code will never be fast without an IR, because it will basically just allow for peephole optimizations. I know one or two ingenious people who compiled to x86 assembler, because it was considered the fastest option then, and now regret that choice.
Many lisps in fact generate native code, in Common Lisp you can even use "disassemble" to get the native code generated for a function
Also, even an interpreter of "intermediate code" can (dynamically) translate that intermediate code to native code. That's how many JVMs work, for example.
[0] https://news.ycombinator.com/user?id=Annatar
Take for example their comment on distributing your product as docker container, forcing your customer to infrastructure they may not have. Many people may not think of it that way but it's definitely a valid concern.
I dunno the world is a weird place :D
But part of me agrees and wants things to go further, since "machine code" is just an abstraction on the microcode. x86 is too high of a layer for what's actually going on in modern CPUs and I hate that to write the most optimal code by hand you have to layout the assembly in a way that coerces the CPU to do what you want at the lower layer (and coerce the compiler to layout the assembly that way too if you aren't working at the assembly layer). At least FPGAs offer salvation to mostly do what you want without lower interference (but there are no "pure" FPGAs, i.e. they actually contain dedicated hardware like DSP slices they can use to be competitive for common tasks rather than just pure programmable gates), but then you're going to be fairly application specific instead of having something more general purpose with lower level hooks or a meta protocol that can give you choices on the tradeoffs instead of being forced to use the one the creators chose. I guess the complaint is that there's just lots of performance left on the table that can't be captured generally.
Compare the efficiency of the same Java machine code compilers in AOT mode to them in JIT mode - JIT is more efficient for anything beyond short-living programs.
That doesn't address your concern about distribution - so that does still remain.
More efficient when compared to itself, but still extremely slow and inefficient compared to a straight machine code binary executable.