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 under lambda/js/ (engine, language, standard library, RegExp, typed arrays, async/modules, Web/DOM, Node.js compatibility) plus the test infrastructure. Convention: the detailed docs cite file:line + symbol names; line numbers drift, so confirm against the symbol. This document supersedes the older doc/dev/JS_Runtime.md and doc/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 Item values (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 DomElement trees 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.

C4 system context

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.

C4 container view

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.

C4 engine components

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

Compilation pipeline overview

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

DocCovers
JS_01 — Compilation Pipeline & Phase ModelEntry points, JsMirTranspiler, the 14-step phase model, interpreter-vs-JIT selection, MIR import resolution, CLI/batch dispatch.
JS_02 — Parsing, AST & Front-End ValidationTree-sitter integration, the JsAstNode model, lexical scope, the six-phase early-error validator, strict-mode detection.
JS_03 — Value Model, Memory & GC InteropThe 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 & ExceptionsBoxed-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

DocCovers
JS_05 — Functions, Closures & ScopeJsFunction, native/boxed dual versions, parameter inference, capture analysis, the scope-environment model, this/arguments/new.target, TCO, inlining.
JS_06 — Objects, Properties & PrototypesMap/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 — ClassesClass collection, constructor compilation, prototype/static methods, inheritance & super, private members, computed keys, subclassable builtins, devirtualization.
JS_08 — Iterators, Generators & DestructuringThe iterator protocol & done sentinel, fast-path iterators, for-of compilation with IteratorClose, generator state machines, destructuring & spread/rest.

Part III — Runtime services

DocCovers
JS_09 — Async, Promises, Event Loop & ModulesJsPromise & 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 LibraryThe built-in registry, Object/Reflect, Symbol, JSON, Math/Number, Date, collections (Map/Set/Weak*), Proxy, BigInt, global functions, template literals, globalThis.
JS_11 — RegExp EngineJsRegexData, 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 & AtomicsJsTypedArray/JsArrayBuffer/JsDataView, element access & the native-backed map, resizable buffers & transfer, detach validation, raw bulk paths, Atomics & waiters, Node Buffer.

Part IV — Host integration

DocCovers
JS_13 — Web Platform: DOM, CSSOM, Events & FetchThe 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 LayerModule 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

DocCovers
JS_15 — Performance & OptimizationThe 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 InfrastructureThe 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:

  • Item everywhere. Every JS value is a 64-bit tagged Item; objects are Lambda Map structs with a TypeMap shape. This is what makes interop with Lambda's parsers/formatters and Radiant free. (JS_03, JS_06)
  • MapKind exotic dispatch. A 4-bit map_kind in 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__) to ShapeEntry flags + JsAccessorPair + a JsClass byte; 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 fs async 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 globalThis is 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_06JS_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).