[HN Gopher] Retrofitting JIT Compilers into C Interpreters
___________________________________________________________________
Retrofitting JIT Compilers into C Interpreters
Author : ltratt
Score : 121 points
Date : 2026-04-15 12:00 UTC (1 days ago)
(HTM) web link (tratt.net)
(TXT) w3m dump (tratt.net)
| sgbeal wrote:
| i tend to think of myself as a computing nerd, but posts like
| this one make me realize that i don't even rate on the computing
| nerd scale.
| throwaway1492 wrote:
| Do you always make things about yourself? Have you written a
| parser or interpreter? You should, it's an interesting
| exercise. The idea is to add meta tracing to the interpreter
| (the c code) that allows hot paths to be compiled to machine
| code and be then executed instead of being interpreted.
| sgbeal wrote:
| > Do you always make things about yourself?
|
| That's an abrasive question but i dare say that we all do.
| It's our only constant point of reference.
|
| > Have you written a parser or interpreter?
|
| i have written many parsers, several parser generators, and a
| handful of programming languages. This article, however,
| covers a whole other level, way over my head (or well beyond
| any of my ambitions, in any case).
|
| Pics or it didn't happen: fossil.wanderinghorse.net/r/cwal
| mwkaufma wrote:
| TL;DR compile with a fork of LLVM that enables runtime IR
| tracing. Very clever!
| measurablefunc wrote:
| That's not what they're doing. They're directly modifying the
| IR to convert it into a tracing JIT. The final artifact is a
| binary w/ no IR. The problem is of course not introducing any
| subtle bugs in the process b/c they'd have to prove the
| modification they're making do not change actual runtime
| semantics for the final binary artifact.
| fuhsnn wrote:
| Took me a while to figure out whether it's interpreters for C
| programs or if there's a particular class of interpreters called
| "C". Turns out it's about interpreters implemented in C that they
| use modified LLVM to do the retrofitting, but couldn't it be
| applicable for other languages with LLVM IR, or other switch-in-
| a-loop patterns in C?
| itriednfaild wrote:
| I've been a low level C and C++ programmer for 30 years. Even
| with your explanation and having read the webpage twice I have
| no idea what this technology does or how it works. So it takes
| normal interpreted code and jits it somehow? But you have to
| modify the source code of your program in some way?
| fuhsnn wrote:
| I don't fully grasp it either, the most appropriate analogy I
| can think of is like how OpenMP turns #pragma annotated loops
| into multi-threading, this work turns bytecode interpreting
| loops into JIT VM.
| moardiggin wrote:
| It's a promising technology, but it's still in the research
| domain. It's not an automated procedure. You need to use
| the yk fork of LLVM to compile and link your code, and you
| have to manually annotate and alter a fair amount of your
| interpreter loop with yk macros in non-trivial ways:
| while (true) { __yk_tracebasicblock(0);
| Instruction i = code[pc]; switch (GET_OPCODE(i))
| { case OP_LOOKUP:
| __yk_tracebasicblock(1);
| push(lookup(GET_OPVAL())); pc++; break;
|
| ... case OP_INT:
| push(yk_promote(constant_pool[GET_OPVAL(i)])); pc++; break;
|
| Knowledge of tracing compilers, LLVM and SSA are needed by
| the user.
|
| > added about 400LoC to PUC Lua, and changed under 50LoC
|
| Lua 5.5.0 has 32106 lines of code including comments and
| empty lines. The changes amount to 1.4% of the code base.
| And then there's the code changes in the yk LLVM fork that
| you'd have to maintain which I'm guessing would be a few
| orders of magnitude larger.
|
| If this project would be able to detect the interpreter
| hotspots itself and completely automate the procedure, it
| would be great.
| ltratt wrote:
| > If this project would be able to detect the interpreter
| hotspots itself and completely automate the procedure, it
| would be great.
|
| I don't think that's realistic; or, at least, not if you
| want good performance. You need to use quite a bit of
| knowledge about your context to know when best to add
| optimisation hints. That said, it's not impossible to
| imagine an LLM working this out, if not today, then
| perhaps in the not-too-distant future! But that's above
| my pay grade.
| moardiggin wrote:
| Thanks for sharing this technology. I hope it gets
| upstreamed into LLVM.
| hencq wrote:
| I think the website does an amazing job explaining it, but it
| basically takes an interpreter written in C and turns it into
| a JIT with minimal changes to the code of the interpreter
| (i.e. not to the code of the program you're running in the
| interpreter). For example they took the Lua interpreter and
| with minimal changes were able to turn it into a JIT, which
| runs Lua programs about 2x faster.
| vkazanov wrote:
| tracing jits are slightly harder to grasp than usual ones.
| The technique comes from real CPUs so the mindset of people
| behind the original idea is very different from the software
| world.
|
| Metatracing ones are kind of an interesting twist on the
| original idea.
|
| > So it takes normal interpreted code and jits it somehow?
|
| Anyway, they use a patched LLVM to JIT-compile not just
| interpreted code but the main loop of the bytecode
| interpreter. Like, the C implementation itself.
|
| > But you have to modify the source code of your program in
| some way?
|
| Generally speaking, this is not normally the goal. All JIT-s
| try to support as much of the target language as possible.
| Some JIT-s do limit the subset of features supported.
| ltratt wrote:
| You're quite right that since we're working with LLVM IR,
| adapting to other languages is probably not _that_ difficult,
| though these things always end up taking more time than I
| expect! Since the majority of real-world problems in this area
| depend on C interpreters, we put our limited resources to that
| problem. You're also right that "interpreters" is a pretty
| vague category, and there are other parts of C (and other)
| programs that could be yk-ified, though I suspect it would be a
| fairly specialised subset of programs.
| pjmlp wrote:
| There were a couple of C interpreters since the 1990's,
| including with REPL support, but apparently never took off,
| most likely a community culture issue, that doesn't seem much
| value using them, beyond being in a debug session.
| i_don_t_know wrote:
| I used to work on LabWindows/CVI an integrated C development
| environment. It included an "Interactive Execution Window"
| where you could build programs piecemeal. You added pieces of
| code, ran them, then appended more code, ran the new pieces,
| etc. It was as text window so you had more freedom than in a
| simple REPL.
|
| It integrated with "Function panels". Function panels were
| our attempt at documenting our library functions. See the
| second link below. But you could enter values, declare
| variables, etc and then run the function panel. Behind the
| scenes, the code is inserted to the interactive window and
| then run. Results are added back to the function panel.
|
| These also worked while suspended on a breakpoint in your
| project so available while debugging.
|
| My understanding was that these features were quite popular
| with customers. They also came it handy internally when we
| wrote examples and did manual testing.
|
| https://www.ni.com/docs/de-DE/bundle/labwindows-
| cvi/page/cvi...
|
| https://www.ni.com/docs/de-DE/bundle/labwindows-
| cvi/page/cvi...
|
| https://irkr.fei.tuke.sk/PPpET/_materialy/CVI/Quick_manual.p.
| ..
| pjmlp wrote:
| Thanks for sharing.
|
| Yeah, I find this valuable regardless of the programming
| language, ideally the toolchain should be a mix of
| interpreter/JIT/AOT, to cherry pick depending on the
| deployment use case.
|
| Naturally for dynamic languages pure AOT is not really
| worth it, althought a JIT cache is helpful as alternative.
| djwatson24 wrote:
| It's quite impressive they're able to take nearly arbitrary C and
| do this! Very similar to what pypy is doing here, but for C, and
| not a python subset.
|
| However not without downsides. It sounds like average code is
| only 2x faster than Lua, vs. LuaJit which is often 5-10x faster.
| hypercube33 wrote:
| Hmm I'm wondering how hard it would be to redo the old timey
| Microsoft jvm from the 90s for modern days....java > .net
| assembly runtime
| linzhangrun wrote:
| It's truly a good thing to see a project like this in the era of
| Vibe Coding taking flight :)
| measurablefunc wrote:
| Why do they need to change LLVM? Why can't they make this another
| LLVM IR pass?
| ltratt wrote:
| Our fork of LLVM does add a pass, amongst other changes, but we
| also have to do things like change stackmaps in a way that
| breaks compatibility. Whether stackmaps in their current
| incarnation are worth retaining compatibility for is above my
| pay grade! So some of our changes are probably upstreamable,
| but some might be considered too niche for wider integration.
| 9fwfj9r wrote:
| Those interested in this type of work can also visit
| https://cfallin.org/blog/2024/08/28/weval/. The difference is
| that they use this technique to derive an AOT compiler.
| syrusakbary wrote:
| Yeah, the strategy is literally the same
| pjmlp wrote:
| I find rather strange the complaint about compatibility across
| JIT implementations, there is exactly the same problem across any
| programming language with multiple implementations, interpreters,
| compilers, JIT, whatever.
| edmondx wrote:
| Sounds very promising. Although right now I'm working on a
| project together with MLIR.
___________________________________________________________________
(page generated 2026-04-16 23:02 UTC)