Technology Stack

A technical overview of the ERD-TSVM compiler, virtual machine, syscall architecture, and platform targets.

ERD platform architecture

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.

TypeScript Lexer Parser Semantic Analysis Type Checking Capture Analysis Optimiser Code Generation Linker ERD1 Bytecode

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.

LevelNameDescription
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.

SectionKey Options
compilerOptionsoptimizationLevel (0โ€“3), strict, snapshot, target (esp32/desktop/wasm), dynamicRegisters, encodeBytecode
compilerOptions.pathsModule path aliases โ€” map @scope/pkg/* to local directories, like pnpm workspaces
manifestmoduleName, version, heapBudget, capabilities, timers, features
debuggenerateSidecar, sidecarPath โ€” debug metadata for DAP debugging
verbosePer-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.

AspectDetails
FormatERDS binary โ€” 56-byte header + object table + root table (format v4)
ValidationCRC-32 hashes for runtime build, intrinsic registry, and bytecode โ€” stale snapshots auto-rejected
Root KindsPersistentHandle, IsolateMainSlot, ModuleGlobal, ConstantPoolEntry
Compiler speedup27.6 s โ†’ 336 ms (82ร—)
Restore mechanismSingle memcpy โ€” no parsing, no execution, no prototype chain construction
DeterminismNon-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.

ComponentDetails
RegistersUp to 256 per frame (dynamic mode) with automatic spilling
Stack FramesCall stack with saved registers, return address, scope chain, exception handlers
Garbage CollectorGenerational collector optimised for low-latency on constrained devices
Fiber SchedulerCooperative async fibers for Promise/async-await โ€” no OS threads
Super InstructionsFused instruction patterns for reduced dispatch overhead
Language ComplianceFull 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.

TypeScript Call Compiler SYSCALL Instruction Domain Dispatcher Platform 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.

DomainCapabilitiesAsync Support
TimersetTimeout, setInterval, clearTimeout, clearIntervalInherent
EventsSubscribe, unsubscribe, wait, event-driven patternsInherent
FilesystemRead, write, stat, mkdir, readdir, rename, deleteYes
HTTPClient requests, server hosting, streamingYes
WebSocketClient/server connections, message framingYes
MQTTPublish, subscribe, QoS, retained messagesYes
NetworkTCP sockets, UDP datagramsYes
DocStoreDocument CRUD, indexing, aggregationYes
GPIODigital I/O, touch, encoder, IR, stepperโ€”
UARTSerial communicationโ€”
I2C / SPIBus protocolsโ€”
ADC / DAC / PWMAnalog I/O, pulse-width modulationโ€”
Camera / DisplayCamera capture, display renderingโ€”
CryptoHashing, encryption, secure randomโ€”
Data FormatsJSON5, TOON, CBOR, MessagePack, Protocol Buffersโ€”
CompressionZlib/DEFLATE/gzip, Zstandard (one-shot and streaming)โ€”
ArchivesZIP (with DEFLATE), TAR (with gzip)โ€”
CRCCRC-8, CRC-16, CRC-32 checksumsโ€”
AuthJWT signing and verification (HS256/384/512)โ€”
ModuleDynamic 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.

ESP-IDF FreeRTOS GPIO WiFi BLE OTA 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.).

Linux macOS Windows UART AI/ML

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.

Emscripten Web Serial WebGPU OPFS

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.