LambdaJS Runtime
June 16, 2026 · View on GitHub
The index and architectural summary for the LambdaJS detailed-design set. LambdaJS is Lambda's embedded JavaScript engine: it compiles JavaScript to MIR and runs it inside the same
Item/GC runtime as Lambda scripts, so JS values, the garbage collector, the MIR JIT, the input parsers/formatters, and the Radiant HTML/CSS layout engine are all shared rather than bridged. Audience: engine developers. Scope: everything underlambda/js/(engine, language, standard library, RegExp, typed arrays, async/modules, Web/DOM, Node.js compatibility) plus the test infrastructure. Convention: the detailed docs citefile:line+ symbol names; line numbers drift, so confirm against the symbol. This document supersedes the olderdoc/dev/JS_Runtime.mdanddoc/dev/JS_Runtime_Detailed.md, whose content has been absorbed and reorganized into the set below.
1. What LambdaJS is, and its design goals
LambdaJS reuses Lambda's runtime instead of shipping a separate JS VM. A .js source is parsed by Tree-sitter, lowered through a typed AST to MIR IR, and JIT-compiled (or interpreted) by the shared MIR backend; the resulting code calls a large C/C++ runtime that implements JS semantics over Lambda Item values. The design optimizes for four goals, each visible throughout the set:
- Unified runtime — JS values are Lambda
Itemvalues (no marshalling boundary); see JS_03 — Value Model & Memory. - Near-native performance — multi-phase type inference plus native arithmetic / shaped-object / fast-dispatch paths; see JS_15 — Performance & Optimization.
- DOM integration — JS manipulates Radiant
DomElementtrees through standard DOM/CSSOM APIs; see JS_13 — Web Platform. - Reuse over reimplementation — JSON, URL, regex (RE2), interning, the GC, and the JIT are shared Lambda subsystems, not JS-specific copies.
2. Architecture (C4)
2.1 System context
The engine lives inside the Lambda software system; developers drive it through the CLI, and the Node.js compatibility layer reaches the host OS/network and the npm registry.
2.2 Containers
The CLI dispatches into the LambdaJS engine, which sits on the shared Lambda runtime (Item model, GC, name pool, MIR JIT, I/O) and drives the Radiant layout engine for document/DOM work.
2.3 Engine components
Inside the engine, a front-end feeds a multi-phase MIR transpiler; the runtime core implements values/properties/functions/exceptions and dispatches into the standard library, the async/module subsystem, and the host bridges. Each component maps to one or more documents in §4.
The C4 diagrams are authored as a Structurizr DSL workspace (
diagram/architecture.dsl) and rendered to SVG; see §7.
3. Compilation & execution at a glance
Source → Tree-sitter parse → typed JsAstNode → early-error validation → a 14-step lowering pipeline producing a MIR module → link as native code (default) or the MIR interpreter (large/cold/document scripts) → execute js_main → drain the event loop → result. The full pipeline, phase model, and interpreter-vs-JIT policy are in JS_01 — Compilation Pipeline & Phase Model.
4. The document set
The set is organized in five parts. Read JS_01–JS_04 first for the engine; the rest can be read on demand.
Part I — Engine core
| Doc | Covers |
|---|---|
| JS_01 — Compilation Pipeline & Phase Model | Entry points, JsMirTranspiler, the 14-step phase model, interpreter-vs-JIT selection, MIR import resolution, CLI/batch dispatch. |
| JS_02 — Parsing, AST & Front-End Validation | Tree-sitter integration, the JsAstNode model, lexical scope, the six-phase early-error validator, strict-mode detection. |
| JS_03 — Value Model, Memory & GC Interop | The tagged Item, JS↔TypeId mapping, undefined/null/TDZ/symbol/BigInt encodings, GC heap & nursery, the call-argument stack, module-variable storage, JsRuntimeState. |
| JS_04 — MIR Lowering, Code Generation & Exceptions | Boxed-Item-by-default emission with native fast paths, boxing/unboxing, condition _raw facades, constant folding, call emission, the exception model, eval/Function. |
Part II — Language semantics
| Doc | Covers |
|---|---|
| JS_05 — Functions, Closures & Scope | JsFunction, native/boxed dual versions, parameter inference, capture analysis, the scope-environment model, this/arguments/new.target, TCO, inlining. |
| JS_06 — Objects, Properties & Prototypes | Map/TypeMap/ShapeEntry, the JSPD_* flag model, MapKind dispatch, get/set pipelines, defineProperty, the prototype chain, built-in method dispatch, symbol keys, shape pre-allocation. |
| JS_07 — Classes | Class collection, constructor compilation, prototype/static methods, inheritance & super, private members, computed keys, subclassable builtins, devirtualization. |
| JS_08 — Iterators, Generators & Destructuring | The iterator protocol & done sentinel, fast-path iterators, for-of compilation with IteratorClose, generator state machines, destructuring & spread/rest. |
Part III — Runtime services
| Doc | Covers |
|---|---|
| JS_09 — Async, Promises, Event Loop & Modules | JsPromise & the resolution procedure, the microtask/job queue, the libuv event loop, async/await suspension, ES modules, top-level await, dynamic import, CommonJS require. |
| JS_10 — Standard Built-in Library | The built-in registry, Object/Reflect, Symbol, JSON, Math/Number, Date, collections (Map/Set/Weak*), Proxy, BigInt, global functions, template literals, globalThis. |
| JS_11 — RegExp Engine | JsRegexData, the RE2/wrapper/backtracking back-ends, JS→RE2 transpilation & post-filters, named groups, /d and /v, Unicode tables, caching, legacy statics. |
| JS_12 — TypedArrays, Binary Data & Atomics | JsTypedArray/JsArrayBuffer/JsDataView, element access & the native-backed map, resizable buffers & transfer, detach validation, raw bulk paths, Atomics & waiters, Node Buffer. |
Part IV — Host integration
| Doc | Covers |
|---|---|
| JS_13 — Web Platform: DOM, CSSOM, Events & Fetch | The sentinel DOM bridge over Radiant, element/document dispatch, lazy layout & metric queries, the 3-phase event system, CSSOM, canvas/measureText, XHR/fetch/FormData/clipboard, Selection. |
| JS_14 — Node.js Compatibility Layer | Module dispatch & resolution, the npm client, per-module coverage (fs/path/os/buffer/crypto/stream/http/net/tls/child_process/…), Buffer, EventEmitter, the event-loop integration status. |
Part V — Cross-cutting
| Doc | Covers |
|---|---|
| JS_15 — Performance & Optimization | The optimization catalog (call-arg stack, const folding, native/dual versions, MapKind, shape pre-alloc, TA raw paths, registry reduction), interpreter-vs-JIT trade-offs, benchmark findings, open gaps. |
| JS_16 — Testing & Conformance Infrastructure | The test262 batch runner, three-layer crash recovery, batch reset, baseline management, the async runner, the Node official-test harness, the GTest unit suites. |
5. Cross-cutting design themes
A handful of decisions recur across the set and are worth knowing before diving in:
Itemeverywhere. Every JS value is a 64-bit taggedItem; objects are LambdaMapstructs with aTypeMapshape. This is what makes interop with Lambda's parsers/formatters and Radiant free. (JS_03, JS_06)- MapKind exotic dispatch. A 4-bit
map_kindin the object header gives plain objects an O(1) fast path and routes exotic objects (TypedArray, DOM, CSSOM, Proxy, iterator, process.env) to dedicated handlers. (JS_06) - Boxed-by-default, native-on-proof codegen. MIR carries boxed
Items unless type inference proves a value and its consumer are numeric, enabling native arithmetic and shaped-slot access without losing generality. (JS_04, JS_15) - JIT with an interpreter escape hatch. Native code is the default; large, cold, or document-embedded scripts link to the MIR interpreter because link-time codegen dominates their cost. (JS_01, JS_15)
- Preamble + batch process model. test262/Node conformance runs compile a shared harness once and then each test against that snapshot inside a persistent, crash-recoverable worker. (JS_01, JS_16)
- An in-progress marker→shape-flag migration. Property metadata is moving from string markers (
__nw_/__get_/__class_name__) toShapeEntryflags +JsAccessorPair+ aJsClassbyte; both schemes currently coexist. (JS_06) - Generator-based async. Async functions reuse the generator state-machine transform; the event loop is libuv with a custom microtask queue layered on top. (JS_08, JS_09)
6. Maturity & recurring known-issue themes
Each detailed doc ends with a code-grounded Known Issues & Future Improvements section. The recurring themes across the set:
- Language & core are mature — ES2020-era language and most built-ins (closures, classes, generators, async/await, modules incl. top-level await, destructuring, Proxy/Reflect, Symbol, BigInt-as-decimal, TypedArrays/Atomics, RegExp via RE2) work and are conformance-tested.
- Benchmark pass rate is not yet 100% — on the standard performance suites (AWFY, JetStream, R7RS, Larceny, Octane, beng, kostya) the engine runs-and-passes ≈88% of the JS scripts (63/72); three wrong-result correctness bugs found by the audit (bounce, levenshtein, crypto-md5) were since fixed, leaving one wrong-result bug (box2d), two feature-path errors, an Octane driver that is not shipped, and several heavy macro-benchmarks that time out. (JS_15 §7)
- Node.js async I/O is the biggest gap — there is a real libuv event loop, but several
fsasync methods call back synchronously and the stream internals are stubs; crypto lacks asymmetric algorithms. (JS_14) - RegExp semantics — RE2's leftmost-longest model differs from JS leftmost-greedy-with-backtracking; a backtracking engine covers part of the gap. (JS_11)
- Approximations — WeakMap/WeakSet have no true weak semantics, per-scope strict mode is approximated by a global flag in eval, and
globalThisis a snapshot. (JS_10, JS_04) - Fixed-capacity statics — generators, promises, modules, the transpiler's collected-function arrays, and several stacks are fixed-size; some lack overflow guards. (JS_01)
- Structure & performance debt — several source files are very large (
js_runtime.cpp,js_globals.cpp, the expression lowering file); float boxing in hot loops and the lack of destination-passing lowering are the main open performance items; compiled-artifact caching is blocked by realm pointers baked into MIR. (JS_15)
7. Diagrams & regeneration
Diagram sources live beside the docs in doc/dev/js/diagram/ and are compiled to the SVGs embedded above:
- Mermaid (
*.mmd) — flow, sequence, state, and class diagrams. - Structurizr DSL (
architecture.dsl) — the C4 system-context / container / component views in §2.
Regenerate everything with bash utils/render_md_diagrams.sh doc/dev/js/diagram (Mermaid → SVG via npx mmdc; Structurizr DSL → per-view SVG via structurizr-cli export to Mermaid, then mmdc). The .dsl path needs a JDK (JAVA_HOME) and structurizr-cli (STRUCTURIZR_CLI); the script prints a skip notice if they are absent. render_md_diagrams.sh doc/dev/js/diagram <name> re-renders specific diagrams.
8. Glossary
- Item — the 64-bit tagged value used for every JS and Lambda value.
- Map / TypeMap / ShapeEntry — a JS object, its shape descriptor, and a per-property record.
- MapKind — the 4-bit exotic-object discriminator in the object header.
- Boxing — tagging a native scalar into an
Item(and unboxing the reverse). - MIR — the medium-level IR that the shared JIT/interpreter consumes.
- Preamble — a pre-compiled shared harness reused across batch tests.
- Marker — a legacy string property (e.g.
__nw_,__class_name__) encoding metadata now carried by shape flags. - Shaped slot — a constructor-pre-allocated, offset-addressed object field.
Appendix — Relationship to the previous docs
This set replaces two earlier documents whose material it absorbs and reorganizes:
doc/dev/JS_Runtime.md(overview) → distributed across this overview, JS_01, JS_03, JS_04, and JS_13.doc/dev/JS_Runtime_Detailed.md(22 sections) → distributed across JS_06–JS_16 by subsystem.
Where the old docs and the code disagreed, the new set follows the code (for example, BigInt is LMD_TYPE_DECIMAL, not a negative-int encoding; the Node.js event loop is real libuv).