Docs / Architecture

8. Triple Execution Model

Dryad's execution engine is not a single interpreter or compiler — it is a three-layer pipeline where each layer feeds the next with progressively richer type information. Layer 1 (AST Interpreter) walks the syntax tree directly and collects runtime type observations for every variable slot, call site, and branch. Layer 2 (Bytecode VM) consumes the AST and the interpreter's type observations to emit type-specialized opcodes — ADD_F64 instead of ADD_GENERIC when the observed type is f64. Each compiled function carries a Metadata Header with the observed type signatures, allowing subsequent layers to skip type inference. Layer 3 (AOT Compiler) reads the type-annotated bytecode and emits LLVM IR with zero type checks for statically-known paths, falling back to guarded branches (fast path with runtime check) only when types are genuinely ambiguous. This design distributes type intelligence across all three layers: the interpreter observes, the VM annotates, and the AOT consumes.

Execution ModeInputType InfoPerformance ProfileUse Case
AST InterpreterSource code (.dryad)Runtime observations collectedFastest startup, slowest executionDevelopment, debugging, rapid iteration
Bytecode VMAST + Type ObservationsMetadata Header: STATIC/OBSERVED/UNKNOWNModerate startup, 10x over interpreterAutomation, scripts, development servers
AOT Compiler (LLVM)Type-Annotated Bytecode (.dryadc)Bind Once: all types resolved at compile time10s startup, native C++ speedProduction binaries, hot paths, deployment
Type-Aware Bytecode Emission
 1 // Dryad source: the interpreter observes that 'sum' is always number
 2 function compute(arr) {
 3   let sum = 0;
 4   for (let i = 0; i < arr.len(); i++) {
 5     sum = sum + arr[i];
 6   }
 7   return sum;
 8 }
 9 
10 // Bytecode emitted by VM (with type observations from interpreter):
11 // Metadata Header:
12 //   FuncID: compute
13 //   Slot 0 (arr): observed f64[]  → confidence: OBSERVED
14 //   Slot 1 (sum): observed f64    → confidence: OBSERVED
15 //   Slot 2 (i):   observed i32    → confidence: OBSERVED
16 //
17 // Emitted opcodes (type-specialized):
18 //   LOAD_CONST 0
19 //   STORE_FAST sum       ; sum: f64
20 //   LOAD_CONST 0
21 //   STORE_FAST i         ; i: i32
22 // .loop:
23 //   LOAD_FAST i          ; i: i32
24 //   LOAD_FAST arr        ; arr: f64[]
25 //   LOAD_FAST i          ; i: i32
26 //   GET_ELEMENT_F64      ; arr[i] as f64 — native load
27 //   ADD_F64              ; sum + arr[i] — native f64 add
28 //   STORE_FAST sum
29 //   ...loop control...
30 //   JUMP_IF .loop

The VM emits type-specialized opcodes (ADD_F64, GET_ELEMENT_F64) based on observations from the interpreter. The Metadata Header pre-populates the AOT compiler's symbol table, eliminating redundant type inference.

@compile() Decorator for Scoped Compilation
 1 // Scoped compilation replaces global set_compile_mode()
 2 // Each @compile() applies only to its annotated scope.
 3 
 4 // Function-level: compile only this function to AOT
 5 @compile("AOT")
 6 function hotPath(data: Buffer) {
 7   // This function is compiled to native even if the
 8   // surrounding module uses interpreter mode
 9   let result = process(data);
10   return transform(result);
11 }
12 
13 // Block-level: compile a specific block to bytecode
14 function mixedMode() {
15   // This part runs in the interpreter (default)
16   let config = io_read_file("config.json");
17   let parsed = json_parse(config);
18 
19   // This block runs in bytecode VM for performance
20   @compile("bytecode") {
21     for (let item in parsed.items) {
22       heavyProcessing(item);
23     }
24   }
25 
26   // Back to interpreter mode
27   return parsed.status;
28 }
29 
30 // The decorator is transitive: functions called from
31 // within @compile("AOT") are also AOT-compiled, unless
32 // they have their own @compile override.

The @compile() decorator provides fine-grained compilation control. It replaces the older set_compile_mode() API and works at both function and block granularity.

Found an error in the spec? Open a PR.
Official Version: 1.0 · May 2026