Bytecode VMs in surprising places (2024)
Recorded: May 25, 2026, 10 a.m.
| Original | Summarized |
Bytecode VMs in surprising places Patrick Dubroy About Bytecode VMs in surprising places Many versions of Unix provide facilities for user-level packet capture, making possible the use of general purpose workstations for network monitoring. Because network monitors run as user-level processes, packets must be copied across the kernel/user-space protection boundary. This copying can be minimized by deploying a kernel agent called a packet filter, which discards unwanted packets as early as possible. The original Unix packet filter was designed around a stack-based filter evaluator that performs sub-optimally on current RISC CPUs. The BSD Packet Filter (BPF) uses a new, register-based filter evaluator that is up to 20 times faster than the original design. So it was originally designed for a pretty restricted use case: a directed, acyclic control flow graph representing a filter function for network packets. And for a long time, the Linux implementation was equally simple: two general-purpose registers, a switch-style interpreter, and no backwards branches. It expands the set of available registers from two to ten, adds a number of instructions that closely match real hardware instructions, implements 64-bit registers, makes it possible for BPF programs to call a (rigidly controlled) set of kernel functions, and more. Internal BPF is more readily compiled into fast machine code and makes it easier to hook BPF into other subsystems. DWARF expressions 2.5 DWARF Expressions It’s up to the debugger to evaluate the expressions. GDB and LLDB both have a switch-based interpreter for DWARF expressions.2 Using GDB’s trace and collect commands, the user can specify locations in the program, and arbitrary expressions to evaluate when those locations are reached. (From Debugging with GDB, Appendix F: The GDB Agent Expression Mechanism) Believe it or not, RAR files can contain bytecode for a simple x86-like virtual machine called the RarVM. This is designed to provide filters (preprocessors) to perform some reversible transformation on input data to increase redundancy, and thus improve compression. His rarvmtools repo includes some details on the architecture: Familiarity with x86 (and preferably intel assembly syntax) would be an advantage. Flexible shaders on the GPU Rather than compiling a model-specific shader program / kernel, Ubershaders: A Ridiculous Solution to an Impossible Problem (2017): Sometimes, one of the best ways to solve an impossible problem is to change your perspective. No matter what we tried, there was no way to compile specialized shaders as fast as games could change configurations. Some others: The TrueType font specification includes a set of over 200 instructions used for glyph rendering and hinting. 👉 Discuss on Hacker News. https://twitter.com/gorilla0513/status/1784623660193677762 ↩ For LLDB, see lldb/source/Expression/DWARFExpression.cpp. For GDB, see gdb/dwarf2/expr.c. ↩ 90s kids will remember. ↩
Hey there! I'm Patrick, a programmer and independent researcher based in Munich, Germany. I'm a co-creator of Ohm, and (with Mariano Guerra) an author of WebAssembly from the Ground Up. © 2006–2026 Patrick Dubroy · Powered by |
The concept of bytecode virtual machines often appears in surprising contexts beyond traditional general-purpose programming languages. This exploration highlights several instances where bytecode execution mechanisms are integrated into systems for efficiency, extensibility, or specialized functionality. One notable example is eBPF, which features an extension mechanism within the Linux kernel that incorporates a bytecode interpreter and a Just-In-Time compiler. eBPF functions as a register-based virtual machine equipped with ten general-purpose registers and over a hundred opcodes. The initial concept, derived from the Berkeley Packet Filter (BPF), originated from an idea to minimize packet copying across the kernel/user-space boundary by deploying a kernel agent. The original BPF design utilized a stack-based filter evaluator, but the BSD Packet Filter evolved into a register-based evaluator that is significantly faster. This evolution involved expanding the system to include more registers, hardware-like instructions, support for 64-bit registers, and the ability for BPF programs to call specific kernel functions, ultimately making the internal system more easily compiled into fast machine code and integrable with other subsystems. Another application involves DWARF expressions, a system introduced to facilitate debug information in compilers. Since the location of local variables in optimized code can be complex, the DWARF specification includes an expression language to describe how to compute or specify a value. These expressions are encoded as streams of operations operating on a stack of values, which debuggers like GDB and LLDB can evaluate using switch-based interpreters. This mechanism is extended into the GDB agent, which employs its own bytecode interpreter for evaluating arbitrary expressions provided by the user when tracing program locations. This GDB agent bytecode operates strictly on machine-level values and requires no knowledge of symbolic types, making the interpreter simple and suitable for real-time execution within the debugging agent. Bytecode also appears in specialized file formats, such as WinRAR. The RAR format includes a bytecode encoding for a RarVM, a simple x86-like virtual machine. This RarVM is designed to facilitate data transformation filters intended to increase redundancy and improve compression. The architecture of RarVM includes named registers for stack operations. Furthermore, bytecode principles are applied in rendering and specification systems. In the context of graphics, there is a design choice to use a general-purpose interpreter and an encoding format for arithmetic expressions that define shapes, rather than compiling model-specific shader programs. This approach focuses on reducing the size of the expression at each recursion level, which is crucial for handling tens of thousands of specialized programs efficiently on the GPU. This idea is further explored in concepts like Ubershaders, which aim to emulate the entire rendering pipeline using a GPU-based interpreter to potentially eliminate shader compilation stuttering. In contrast, other specifications, such as the TrueType font specification, include over two hundred instructions for rendering and hinting, and PostScript, while text-based, also includes a binary encoding layer. These examples demonstrate that the use of bytecode VMs extends across kernel internals, debugging toolchains, file compression, and graphics programming. |