Other Runtimes and Execution Models

Learning Objectives

Describe Lua's VM and embedding, Ruby's YARV, PHP's pipeline and OPcache, Erlang's BEAM and processes, Go's compiler and runtime, Rust's native/AOT model, Swift's runtime, Kotlin/JVM versus Kotlin/Native, Dart's JIT/AOT modes, and R and MATLAB execution.

Recognise SQL engines as planners and interpreters, game scripting, embedded scripting engines and plugin runtimes; compare runtime services and design goals.

Plain-Language Explanation

Not every language runs the same way. Some are compiled straight to machine code and only carry a small runtime (Go, Rust, Swift). Some run on their own virtual machines (Lua, Ruby, Erlang, PHP). Some offer both modes depending on the target (Kotlin, Dart). Even database queries are compiled into little programs for an internal virtual machine.

Precise Technical Explanation

Lua VM and embedding concepts A small register-based VM (Lua 5) written in ANSI C, designed for embedding: the host pushes and pops values on a C API stack, registers C functions, and runs scripts with limits; LuaJIT adds a tracing JIT.

Ruby VM / YARV overview CRuby compiles Ruby to YARV stack bytecode (RubyVM::InstructionSequence), runs it with a GVL, and offers YJIT (a lazy basic-block-versioning JIT) since Ruby 3.1.

PHP execution pipeline and OPcache overview PHP compiles each script to opcodes (Zend VM) per request; OPcache caches compiled opcodes in shared memory across requests; PHP 8 adds a JIT on top.

Erlang BEAM and lightweight processes overview BEAM is a register-based VM running millions of isolated lightweight processes with per-process heaps and GC, preemptive scheduling by reduction counts, message passing, supervision and hot code loading; BeamAsm (OTP 24+) JIT-compiles bytecode to native code at load time.

Go compiler/runtime and goroutines (not typically a user-visible bytecode VM)

Go compiles AOT to native executables that link in a runtime: goroutine scheduler (M:N), growable stacks, a concurrent mark-sweep GC, maps and channels. There is no user-visible bytecode or JIT.

Rust execution and native/AOT compilation model rustc (LLVM) compiles AOT to native code; memory is managed by ownership at compile time; the runtime is minimal (panic handling, start-up); async needs a library executor such as Tokio.

Swift runtime and compilation overview AOT-compiled via LLVM, with a runtime providing ARC reference counting, metadata, dynamic casting, protocol witness tables and Objective-C interop on Apple platforms.

Kotlin/JVM and Kotlin/Native execution differences Kotlin/JVM emits JVM bytecode and runs on any JVM (with its JIT and GC); Kotlin/Native compiles via LLVM to native binaries with its own GC; Kotlin/JS and Kotlin/Wasm target other runtimes.

Dart VM and AOT/JIT deployment modes Dart runs JIT-compiled in development (fast hot reload) and AOT-compiled for release (Flutter apps), or compiles to JavaScript/Wasm for the web.

R and MATLAB execution model overview R evaluates ASTs (with lazy argument promises) and compiles functions to bytecode (the compiler package, enabled by default); MATLAB uses a JIT-accelerated execution engine (since R2015b) over its own IR; both rely on vectorised native libraries for speed.

SQL query engines as interpreters/planners (related but distinct)

SQL is declarative: the planner chooses an execution plan; engines then interpret the plan (Volcano iterators), run vectorised operators, or compile it (code generation). SQLite compiles each statement to bytecode for its VDBE virtual machine (shown below).

Game scripting runtimes Lua, Squirrel, AngelScript, C# in Unity (via Mono or IL2CPP), GDScript in Godot (an interpreter with typed fast paths), Unreal's Blueprints (graph bytecode).

Embedded scripting engines Lua, QuickJS, Duktape, mruby, MicroPython, Wren — small footprints, C APIs, sandboxable.

Plugin runtimes and extensibility Wasm, Lua, JavaScript (V8 isolates), or out-of-process plugins via RPC — chosen by isolation, performance and language needs.

Comparing runtime services and design goals register VM (+ LuaJIT) incremental/generational GC embedding, small size YARV stack VM + YJIT threads with GVL, Ractors register VM + BeamAsm millions of processes AOT native + runtime simple, fast builds and services ownership (no GC) threads, async libraries safety without GC JIT (dev) / AOT (release) UI development speed

Do not force every language into a bytecode/JIT model: Go, Rust and Swift are commonly compiled directly to native code; Kotlin and Dart depend on the target.

Why It Matters in Real Systems

Choosing a language for a service, an embedded scripting layer or a plugin system means choosing its runtime model — start-up, memory, concurrency and deployment follow from it.

Key Terms

Hosting a language runtime inside another application PHP's shared cache of compiled opcodes

Lightweight isolated actor with its own heap SQLite's virtual database engine (bytecode VM)

Replacing code in a running program (Dart JIT, BEAM)

Diagram, Execution Trace or State Transition

Text equivalent: native-compiled languages ship a small runtime; VM-based languages carry an interpreter (sometimes a JIT); managed platforms add tiered JITs and loading; some languages pick a model per target.

flowchart TB
  N[Native AOT: Go, Rust, Swift, Kotlin/Native] --> RT1[small runtime: scheduler, GC or ARC]
  V[Own VM: Lua, CRuby, BEAM, PHP, SQLite VDBE] --> RT2[interpreter, optional JIT]
  M[Managed platform: JVM, CLR, V8] --> RT3[tiered JIT, GC, class/assembly loading]
  H[Target-dependent: Kotlin, Dart] --> N
  H --> M

Syntax or Instruction Format

No dedicated source syntax; this is a runtime or architecture concept.

Complete Example

SQLite compiles SQL into bytecode for its VDBE virtual machine — EXPLAIN prints it (SQLite as shipped with CPython 3.13.1; opcodes and addresses are SQLite-version specific):

Go: a native executable with a runtime but no bytecode — goroutines, the scheduler's parallelism setting and the GC are runtime services (Go 1.23.4, Windows; numbers from one real run):

import sqlite3

con = sqlite3.connect(":memory:")
con.execute("CREATE TABLE t(x INTEGER)")
con.executemany("INSERT INTO t VALUES (?)", [(1,), (5,), (9,)])
print("SQLite", sqlite3.sqlite_version)
print("result:", con.execute("SELECT x * 2 FROM t WHERE x > 3").fetchall())
for addr, opcode, p1, p2, p3, p4, p5, comment in con.execute("EXPLAIN SELECT x * 2 FROM t WHERE x > 3"):
    print(f"{addr:>3}  {opcode:<12} {p1:>3} {p2:>3} {p3:>3}  {p4 if p4 is not None else ''}")
SQLite 3.45.3
result: [(10,), (18,)]
  0  Init           0  10   0
  1  OpenRead       0   2   0  1
  2  Rewind         0   9   0
  3  Column         0   0   1
  4  Le             2   8   1  BINARY-8
  5  Column         0   0   1
  6  Multiply       4   1   3
  7  ResultRow      3   1   0
  8  Next           0   3   0
  9  Halt           0   0   0
 10  Transaction    0   0   1  0
 11  Integer        3   2   0
 12  Integer        2   4   0
 13  Goto           0   1   0
package main

import (
	"fmt"
	"runtime"
	"sync"
)

func main() {
	fmt.Println("compiled for", runtime.GOOS+"/"+runtime.GOARCH, "with", runtime.Version())
	var wg sync.WaitGroup
	results := make([]int, 1000)
	for i := 0; i < 1000; i++ {
		wg.Add(1)
		go func(i int) { defer wg.Done(); results[i] = i * i }(i) // 1000 goroutines, scheduled by the Go runtime
	}
	wg.Wait()
	sum := 0
	for _, r := range results {
		sum += r
	}
	var stats runtime.MemStats
	runtime.GC()
	runtime.ReadMemStats(&stats)
	fmt.Println("sum of squares:", sum, "| goroutines now:", runtime.NumGoroutine(), "| completed GC cycles >= 1:", stats.NumGC >= 1)
}
compiled for windows/amd64 with go1.23.4
sum of squares: 332833500 | goroutines now: 1 | completed GC cycles >= 1: true

Line-by-Line Explanation

SQLite: the statement becomes a small program — open a cursor on table t (OpenRead), loop over rows (Rewind/Next), read the column, compare with 3 (Le jumps past rows that fail), multiply, ResultRow, then Halt. It is a register-based VM: operands name registers (p1–p3).

Go: the executable is native code; goroutines are multiplexed onto OS threads by the runtime scheduler; runtime.GC() runs the concurrent collector.

Expected Output

Results are deterministic ([(10,), (18,)], 332833500); opcode listings depend on the SQLite version.

Step-by-Step Runtime Behavior

SQLite: Init jumps to the transaction setup, then back to the loop; for each row, the comparison either skips or computes and emits a result row.

Common Misconceptions

"Go has a VM." It has a runtime, not a bytecode VM.

"SQL is executed directly." It is planned and compiled into an execution program.

"Erlang processes are OS processes." They are lightweight VM processes.

Common Bugs and Failure Modes

Assuming JIT-style warm-up in AOT languages (or the reverse), embedding scripting engines without limits, PHP without OPcache in production, GVL/GIL surprises in Ruby and Python threading.

Corrected or Safer Patterns

Profile with each runtime's own tools; sandbox embedded engines (instruction limits, restricted standard libraries); enable OPcache; use processes or Ractors/isolates for CPU parallelism.

Debugging and Inspection Techniques

luac -l, RubyVM::InstructionSequence.disasm, opcache_get_status, :observer.start() (Erlang), go tool pprof, EXPLAIN/EXPLAIN QUERY PLAN.

Performance Considerations

Native AOT: fast start, no warm-up. VM languages: interpreter overhead unless JIT-compiled. Database engines: plan quality outweighs execution speed.

Security Considerations

Embedded engines need restricted libraries and limits; SQL needs parameterised queries (the plan is compiled from the statement text — injection changes the program).

Portability and Version Caveats

Bytecode formats (YARV, Lua, VDBE) are internal and versioned; JIT availability varies by platform and build.

Real-World Use Cases

Lua in Redis, Nginx (OpenResty) and games; Erlang/Elixir in telecom and messaging; Go in cloud infrastructure; SQLite in every phone; Dart in Flutter apps.

Best Practices

Match the runtime model to the workload, and do not assume one runtime's behaviour applies to another.

Exercises

E1 · Beginner. Which of these normally have a user-visible bytecode format: Go, Lua, Java, Rust?

Answer: Lua (luac output) and Java (class files). Go and Rust compile to native code.

E2 · Intermediate. Why is SQL injection an attack on a compiler?

Answer: The database compiles the statement text into an execution program; injected text changes the program itself, not just its data — parameters keep data out of the compiled code.

E3 · Advanced challenge. When would you embed Lua rather than Wasm for game scripting?

Answer: Lua when designers write scripts directly, fast iteration and a tiny embeddable interpreter matter, and the host API is rich and dynamic; Wasm when scripts come compiled from several languages, need near-native speed and stronger memory isolation, at the cost of more complex tooling and host bindings.

Quiz

? Which runtime uses millions of lightweight processes with per-process heaps?
+ Erlang's BEAM :: Isolated processes with message passing.
- CPython :: Threads with a GIL.
- Go :: Goroutines share one heap.
- SQLite :: Single statement VM.

? What does SQLite's EXPLAIN show?
+ The bytecode program its VDBE runs for a statement. :: SQL is compiled before execution.
- The SQL text. :: It shows the compiled program.
- Machine code. :: VDBE bytecode.
- The table data. :: No.

? Which are commonly compiled ahead of time to native code? (select all that apply)
+ Go :: With a runtime for goroutines and GC.
+ Rust :: Via LLVM.
- PHP :: Opcodes in the Zend VM.
+ Swift :: Via LLVM, with an ARC runtime.

Summary and Key Takeaways

Execution models range from native AOT with small runtimes (Go, Rust, Swift) through dedicated VMs (Lua, Ruby, BEAM, PHP, SQLite's VDBE) to target-dependent toolchains (Kotlin, Dart). Each runtime's services and design goals — embedding, fault tolerance, start-up, safety — explain its behaviour.

Further Reading

Ierusalimschy et al., "The Implementation of Lua 5.0"; *Programming in Lua*, embedding chapters.

SQLite documentation, "The SQLite Bytecode Engine".

Erlang/OTP documentation, "BEAM — the Erlang VM"; The Go Programming Language Specification and runtime package docs.