Join the discussion

Write your take first — we'll ask for email only when you're ready to publish.

  • Hacker News
  • Nice
  • Tcc be like
  • Didn't know that
  • It uses copy-and-patch compilation to archive that
  • pgrust sounds very interesting, but with the deep changes there’s no viable path to upstream it - is the end goal to be robust enough that it’ll get wide adoption?
  • Is it really interesting though? It's essentially just vibe-coded by people who are unqualified for this kind of work. One of the authors claimed that what qualified them was having worked on a large-scale postgres cluster; they never actually worked on databases or compilers.
  • Author here. Let me know if you have any questions about the post or about pgrust.
  • There’s been a meme circulating about how AI doesn’t help because “code was never the hard part.” I think that’s true in some domains, but in others, writing the code absolutely was the hard part. JIT compilers are a great example of that.
  • Anyone who thinks AI is good with writing code that is hard to write for the operator, not due to lack of basic software engineering know how but complexity of the domain, either has access to models beyond what is available to the public or is completely lost.

    I believe this because every time I use AI for domains that I consider myself above competent, if it is anything beyond UI components or a simple CRUD endpoints, I cringe at the quality of what it generates.

    This has made me to be extremely cautious of starting working in a new domain with AI if I want anything beyond throw away quick hacks or junk, shy of quick bug fixes perhaps.

  • The problem with the approach is that it's not real JIT-compilation, it's just assembly templates with basic substitutions.

    By not using LLVM, you're missing all the optimizations it does.

  • > By not using LLVM, you're missing all the optimizations it does

    And yet, a good portion of software that runs today's world is written in scripting languages & executed using interpreters.

    Which is okay! Imho: multiply [# of users] with [how often each user sees that software's effect] and [how much that contributes to the overall user experience], then you get a ballpark idea of how much $$/effort is worth spending on optimization.

    In other words: for a one-off, don't bother. But as usercount, frequency of use by individual users, poor UX or RAM/CPU consumption goes up, progress from script -> compiled -> optimizing compiler -> (if necessary) hand-optimized assembly as needed. And of course consider high-level design, data structures, algorithms etc in that process. A change there might be more effective than a switch from interpreted -> optimizing compiler.

    "Developer time" should not factor into that much (again: imho) unless users=developers.

    Thoughtlessly putting every change through a (slow?) pipeline that does 'random' toolbox-of-optimizations without need, is wasteful. Apply that toolbox as needed while keeping the above in mind.

  • This absolutely is real JIT compilation. Copy and patch is a very well known JIT compilation technique.
  • By choosing LLVM you're also taking a serious latency hit, and potentially burning a ton of CPU cycles on optimizations that will never apply. JSC, for instance, implemented LLVM for FTLJIT (which is where many of the JS bits jangling around in LLVM originated from), but it was only useful for code that was highly likely to benefit from the optimizations because of the high cost of compilation. The webkit folks have since ripped out LLVM and replaced it with their own specialized JIT, which is essentially just what's demonstrated here (with some optimization passes).
  • Sounds like a "no true Scotsman" statement. How are you defining "real"?

    Some human, somewhere, has to describe how to turn high-level language constructs into machine code. "When you see this pattern, emit this sequence of bytes." That's just templates and stencils. There's no magic for turning source code into machine code by divining the ISA at compile time.

    Anything that's taking source code and, at the time of execution, is compiling it to machine code on-the-fly is JIT compilation. Regardless how long it takes, lack of optimization, or which machine is the target (x86, ARM32/64, RISC-V, JVM, WebAssembly), it's JIT.

  • A non-optimizing compiler is a real compiler.
  • This is absolutely a JIT-compiler. It compiles code into machine code. This is a surprisingly efficient way to get noticeable speedup relative to interpretation. Also it is much safer than proper optimising compiler. Say ebpf jit-compiler functions very similarly, because it is fast and _secure_ way to jit. (well, there's a bit of cheating because before emitting bpf bytecode it goes through gcc/clang pipeline).

    LLVM is a large dependency if you need to JIT. There are plenty of smaller (and much faster) alternatives which are much better fit for smaller projects. Larger projects usually roll out their own jit-pipeline because they can integrate better with the source language/interpreter and apply tricks LLVM is not well suited to (say, LLVM is not great at deoptimisation). I think only Julia is really a heavy user of LLVM JIT, also it is known for extremely slow repl from time to time.

  • Uhm, Common Lisp, where JIT is not only available but is also manageable: the programmer can decide what deserves to be compiled and what does not.

    Besides run time, JIT is available also when the code is compiled or loaded for execution (i.e., do you have a compilation or loading speed-up in mind? no problem, you can also compile that speed-up into native machine code, and so ad infinitum...).

  • is an xtensa lx7 (esp32-s3) target available that does not use llvm?
  • Not in typical builds of SBCL: all code is compiled before evaluation.
  • This is perhaps a little meta, but this was a pleasant read. It’s refreshing to read an article about using an LLM that doesn’t read like it was also written by that LLM.

    I might use this approach to generate the stencils for a JIT firewall I’ve been experimenting with.

    It also occurs to me that this could be used to generate eBPF byte code on the fly as well

  • I recommend Russ Cox's articles on implementing a regex engine: https://swtch.com/~rsc/regexp/

    It is very relevant

  • Reminds me of the 2024 blog post Look ma, I wrote a new JIT compiler for PostgreSQL [0]. Both articles lament that Postgres's LLVM-based JIT [1] takes a while to generate code.

    > The rarity of JIT compilers makes me believe that implementing a JIT compiler historically was too difficult for it to be worthwhile.

    That's only true of writing a JIT from scratch. There's no rarity of JITs, it's just that LLVM (and other frameworks) are often used. Every major interpreter has a JIT compiler. PCRE2 has a JIT compiler. There are JIT frameworks out there with much faster code-generation than LLVM: Cranelift, GNU Lightning, Mir. I doubt they could do code-generation faster than a custom copy-and-patch JIT, but they'd be much faster than LLVM.

    [0] https://www.pinaraf.info/2024/03/look-ma-i-wrote-a-new-jit-c... , discussed: https://news.ycombinator.com/item?id=39742916

    [1] https://www.postgresql.org/docs/current/jit-reason.html

  • The original Dartmouth BASIC had a JIT like approach, the REPL would compile to machine code before execution.

    It was the limits of 8 bit home computers hardware that made the interpreter version be more widely known.

    Same to Lisp, Smalltalk, and many other languages.

    Fully agree with you.

  • > There's no rarity of JITs, it's just that LLVM (and other frameworks) are often used

    Except that using LLVM has high latency limitting it's applicability. Postgres just disabled LLVM by default because of this[0].

    [0] https://www.postgresql.org/message-id/E1w8GWU-002bSL-31%40ge...

  • A few other small and fast JITs: https://github.com/zherczeg/sljit (used by libpcre), https://github.com/asmjit/asmjit (RPCS3 and FBGEMM) and https://webkit.org/blog/5852/introducing-the-b3-jit-compiler... (only used by JSC in Webkit, I think)
  • Not sure where the idea comes from that Cranelift is much faster than LLVM -O0, at least in our experiments in 2024 it wasn't, see [1] Fig. 6.

    Template-based code generators suffer from bad code quality due to missing register allocation.

    Our TPDE-based compilers compile a bit slower than template-based code generation but the generated code is much smaller and faster ([2] Fig. 2). Also for database workloads ([2] Fig. 6).

    All that said, Postgres' main limitation is that it (IIRC) only compiles single expressions from operators, not pipelines. This fundamentally limits the achievable performance improvement compared to databases that perform more extensive query compilation.

    [1]: https://aengelke.net/pubs/2403-cgo.pdf [2]: https://aengelke.net/pubs/2602-cgo1.pdf

    PS: sorry for the promotion of my own research here, just couldn't resist.