Technology Stack
A technical overview of the ERD-TSVM compiler, virtual machine, syscall architecture, and platform targets.
Compiler Pipeline
The ERD compiler transforms TypeScript source into compact bytecode through a multi-stage pipeline. Each stage refines the representation, applying type checks, optimisations, and platform-specific code generation.
Frontend
The Lexer tokenises TypeScript source into a token stream.
The Parser builds a full Abstract Syntax Tree (AST) covering
every TypeScript 6.0 construct โ classes, generics, decorators,
using declarations, auto-accessors, and all ES2026 syntax.
Semantic Analysis resolves identifiers, validates scopes,
checks control flow, and performs full TypeScript type checking.
Optimiser
Multi-pass optimisation pipeline: constant folding, dead code elimination, constant propagation, strength reduction, loop-invariant code motion, tail call optimisation, common subexpression elimination, loop unrolling, and type-guided transforms. Four optimisation levels from none to aggressive.
Backend
Capture Analysis identifies variables captured by closures to generate correct upvalue handling. Code Generation emits binary bytecode instructions. The Linker resolves imports across modules, merges sections, and writes the final ERD1 bytecode container.
Decorator Support
TC39 Stage 3 decorators are fully supported and lowered at compile time.
Class, method, getter, setter, and field decorators all work as specified.
Auto-accessor declarations (accessor x = 0) are desugared into
a backing property with generated getter/setter. Decorator context objects
include kind, name, static,
private, addInitializer, access,
and metadata. Symbol.metadata inheritance follows
the specification via prototype chaining.
Optimisation Pipeline
The compiler includes a multi-phase optimisation pipeline that progressively improves code quality and reduces output size. Optimisations include constant folding, dead code elimination, constant propagation, strength reduction, loop-invariant code motion, tail call optimisation, common subexpression elimination, loop unrolling, and type-guided transforms.
Optimisation Levels
Four optimisation levels control how aggressively the compiler optimises. Individual optimisations can also be toggled explicitly.
| Level | Name | Description |
|---|---|---|
| 0 | None | No optimisations. Fastest compilation, largest output. Ideal for debugging. |
| 1 | Size | Minimal code growth. Ideal for ESP32 flash-constrained targets. Conservative loop unrolling. |
| 2 | Balanced | Default. Good size/speed trade-off. Enables partial loop unrolling and type-guided transforms. |
| 3 | Speed | Aggressive unrolling and inlining. Largest output, fastest execution. |
Project Configuration โ erdtsconfig.json
The erdtsconfig.json file configures the compiler per-project.
It follows the same pattern as TypeScript's tsconfig.json โ place it
in your project root and the compiler discovers it automatically. CLI flags
always override config values.
| Section | Key Options |
|---|---|
| compilerOptions | optimizationLevel (0โ3), strict, snapshot, target (esp32/desktop/wasm), dynamicRegisters, encodeBytecode |
| compilerOptions.paths | Module path aliases โ map @scope/pkg/* to local directories, like pnpm workspaces |
| manifest | moduleName, version, heapBudget, capabilities, timers, features |
| debug | generateSidecar, sidecarPath โ debug metadata for DAP debugging |
| verbose | Per-phase logging: parser, semantic, emitter, linker, bundler, optimizer |
Example with path aliases for a multi-package project:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@sensors/*": ["packages/sensors/src/*"],
"@utils/*": ["packages/utils/src/*"]
},
"optimizationLevel": 2,
"snapshot": true,
"target": "esp32"
},
"manifest": {
"moduleName": "sensor-hub",
"version": "1.0.0",
"capabilities": ["gpio", "bus", "mqtt"]
}
}
Heap Snapshot System
The heap snapshot system captures the VM's post-initialisation memory state and
embeds it as a binary section in the .erd bytecode file. On cold start,
the runtime deserialises the snapshot directly into the heap โ skipping all
module imports, class definitions, prototype chains, and constant materialisation.
| Aspect | Details |
|---|---|
| Format | ERDS binary โ 56-byte header + object table + root table (format v4) |
| Validation | CRC-32 hashes for runtime build, intrinsic registry, and bytecode โ stale snapshots auto-rejected |
| Root Kinds | PersistentHandle, IsolateMainSlot, ModuleGlobal, ConstantPoolEntry |
| Compiler speedup | 27.6 s โ 336 ms (82ร) |
| Restore mechanism | Single memcpy โ no parsing, no execution, no prototype chain construction |
| Determinism | Non-deterministic syscalls (I/O, Date.now, Math.random) blocked during snapshot capture |
Capture Pipeline
TypeScript source
โ compile + bundle
.erd bytecode (without snapshot)
โ erd-snapshot-bootstrap
โ 1. Load in fresh Isolate
โ 2. Run $bundled_init to completion
โ 3. Capture heap via HeapSnapshotWriter
โ 4. Splice SNAPSHOT section into .erd
.erd bytecode (with snapshot)
โ runtime cold start
โ 1. Detect SNAPSHOT section
โ 2. Validate CRC-32 hashes
โ 3. Restore heap (skip $bundled_init)
โ 4. Schedule main closure
Program running (up to 82ร faster)
Bytecode Format โ ERD1
The compiler outputs ERD1 bytecode files โ a compact, section-based binary format designed for minimal memory footprint and fast loading on constrained devices. The format supports optional debug information, compressed sections, cryptographic signing, integrity verification via checksums, and heap snapshots for fast cold start.
Virtual Machine
The ERD-TSVM executes compiled bytecode on a register-based architecture with up to 256 general-purpose registers per stack frame, automatic register spilling, a generational garbage collector, super instruction fusion, and an async fiber scheduler.
| Component | Details |
|---|---|
| Registers | Up to 256 per frame (dynamic mode) with automatic spilling |
| Stack Frames | Call stack with saved registers, return address, scope chain, exception handlers |
| Garbage Collector | Generational collector optimised for low-latency on constrained devices |
| Fiber Scheduler | Cooperative async fibers for Promise/async-await โ no OS threads |
| Super Instructions | Fused instruction patterns for reduced dispatch overhead |
| Language Compliance | Full ES2026 semantics, full TypeScript type system |
Memory Management
The runtime uses a generational garbage collector designed for low-latency execution on constrained devices. Short-lived objects are collected quickly via a young generation collector, while long-lived objects are promoted to an old generation with mark-and-sweep collection.
Hidden Classes
Objects with the same properties added in the same order share a hidden class, allowing the runtime to optimise property access by offset rather than dictionary lookup. This technique โ common in production JavaScript engines โ delivers fast property access even on constrained hardware.
Fiber Scheduling
The runtime uses cooperative fibers for concurrency โ no OS threads
are needed, making it ideal for single-core microcontrollers. Each async
function, Promise.then() chain, or timer callback runs in its own fiber.
When a fiber awaits an async operation (I/O, timer, Promise), it suspends and the
scheduler picks the next ready fiber. This model delivers non-blocking I/O with
deterministic execution order and minimal memory overhead.
Event Loop
The runtime implements an event loop with semantics matching browser and Node.js behaviour โ Promise reactions and microtasks are processed before timers and I/O completions, ensuring predictable execution order for async code.
Syscall Architecture
Syscalls bridge TypeScript code and native platform capabilities. When TypeScript calls a standard library function, the compiler emits a syscall instruction. At runtime, the VM dispatches to a platform-specific native handler.
Syscalls are organized into domains โ logical groupings of related functionality. Each domain has its own handler that processes syscalls for its category. All I/O domains support both synchronous and asynchronous modes. In async mode, the calling fiber suspends and is resumed when the operation completes, enabling non-blocking I/O without callbacks or OS threads.
| Domain | Capabilities | Async Support |
|---|---|---|
| Timer | setTimeout, setInterval, clearTimeout, clearInterval | Inherent |
| Events | Subscribe, unsubscribe, wait, event-driven patterns | Inherent |
| Filesystem | Read, write, stat, mkdir, readdir, rename, delete | Yes |
| HTTP | Client requests, server hosting, streaming | Yes |
| WebSocket | Client/server connections, message framing | Yes |
| MQTT | Publish, subscribe, QoS, retained messages | Yes |
| Network | TCP sockets, UDP datagrams | Yes |
| DocStore | Document CRUD, indexing, aggregation | Yes |
| GPIO | Digital I/O, touch, encoder, IR, stepper | โ |
| UART | Serial communication | โ |
| I2C / SPI | Bus protocols | โ |
| ADC / DAC / PWM | Analog I/O, pulse-width modulation | โ |
| Camera / Display | Camera capture, display rendering | โ |
| Crypto | Hashing, encryption, secure random | โ |
| Data Formats | JSON5, TOON, CBOR, MessagePack, Protocol Buffers | โ |
| Compression | Zlib/DEFLATE/gzip, Zstandard (one-shot and streaming) | โ |
| Archives | ZIP (with DEFLATE), TAR (with gzip) | โ |
| CRC | CRC-8, CRC-16, CRC-32 checksums | โ |
| Auth | JWT signing and verification (HS256/384/512) | โ |
| Module | Dynamic import, module resolution | โ |
Platform adapters implement only the syscalls relevant to their target โ unsupported syscalls return a clear error at runtime. This allows the same TypeScript source to compile once and run on any platform, with platform-specific capabilities gracefully degrading where not available.
Platform Targets
ESP32
Targets ESP32-C3, C6, S3, H2, and P4 microcontrollers. Runs on ESP-IDF with FreeRTOS. Full peripheral support: GPIO, WiFi, BLE, I2C, SPI, UART, ADC, DAC, PWM, camera, display, and USB. Supports multiple storage backends (LittleFS, SPIFFS, FAT on SD card), OTA updates with automatic rollback, and secure boot.
Desktop
Runs on Linux, macOS, and Windows. Uses native file I/O, the system network stack, serial port access (termios/Win32), and AI inference with GPU acceleration (CUDA, DirectML, CoreML). Desktop builds support the full syscall surface except hardware-specific peripherals (GPIO, I2C, SPI, etc.).
WebAssembly
Compiled via Emscripten for modern browsers. Executes inside a Web Worker
with browser-safe syscalls. Supports filesystem (OPFS), serial communication
(Web Serial API), AI inference (WebGPU), DocStore, HTTP via
browser fetch(), and the full JavaScript interop layer.
Powers the web playground.
Platform Abstraction
The runtime uses a platform abstraction layer that isolates hardware and OS differences behind portable interfaces. Each platform (ESP32, Desktop, WASM) provides its own implementation. This architecture enables write-once TypeScript code: the same bytecode runs unchanged on a microcontroller, a development laptop, or a web browser.
Security
Security is built into every layer of the stack โ from the bytecode format to the runtime execution model.
Encrypted Storage
All data at rest โ DocStore documents, configuration, credentials โ is encrypted.
Encryption keys are derived from device-specific material and
never stored in plain text. eval() and new Function()
are excluded by design, eliminating runtime code injection vulnerabilities.
Signed Bytecode & OTA
Both bytecode files and firmware updates are cryptographically signed. The runtime verifies signatures before loading or staging. Rollback is automatic if health checks fail after a firmware update.
Secure Boot Chain
Each boot stage verifies the next, ensuring only trusted, signed firmware executes on the device. Unauthorized code is rejected before it can run.
TypeScript Support
ERD-TSVM targets TypeScript 6.0 and the ES2026 specification. The compiler tracks 254+ language features across all ECMAScript editions from ES2015 through ES2026.
Type System
Full TypeScript type checking at compile time: generics with constraints,
conditional types, mapped types, template literal types, union and intersection
types, discriminated unions with narrowing, type predicates, satisfies
operator, const type parameters, and infer with
extends constraints.
Classes & Decorators
Full class support: inheritance, static members, private fields (#name),
abstract classes, override keyword, and TC39 Stage 3 decorators
on classes, methods, getters/setters, fields, and auto-accessors.
Modules & Async
ES Modules with import / export, dynamic
import(), re-exports, and import type.
Full async support: async / await,
generators, async generators, for await...of,
Promise.allSettled(), Promise.any(),
Promise.try(), and top-level await.
Type Erasure
Type annotations are checked during semantic analysis and erased during bytecode generation. There is no runtime type metadata โ consistent with standard TypeScript behavior. This means interfaces, type aliases, and generic constraints have zero runtime cost.