Skip to content
Roger Johansson edited this page Jan 14, 2026 · 11 revisions

Asynkron.JsEngine Wiki

A lightweight JavaScript interpreter written in C# with an IR-based execution model.


Quick Links

Core Concepts

Topic Description
Architecture Overview Execution model, AST vs IR, function variants
JsValue System Value representation and the evaluator overload pattern
JsEnvironment & Slots Variable storage: named, slot, and flat slot access
JsObject & Properties Property descriptors, prototype chains, extensibility
Scope Analysis Hoisting, TDZ, slot assignment, closure capture

Execution

Topic Description
Execution Tiers AST, IR, and planned expression bytecode/IL
IR Execution Instruction types, dispatch table, ExecutionPlanRunner
Generators & Async How generators, async functions, and async generators work
Promise & Microtasks Promise states, microtask queue, await handling
ES Modules Import/export, module loading, live bindings

Standard Library Reference

Type Page Status
Full Index All types overview ~95%
Object keys, values, assign, freeze, etc. 100%
Array map, filter, reduce, sort, etc. 100%
String split, replace, trim, pad, etc. 100%
Number / Math parseInt, isNaN, sin, cos, etc. 100%
Date getTime, setMonth, toISOString, etc. 100%
Promise then, catch, all, race, etc. 100%
Map / Set get, set, has, delete, etc. 100%
RegExp exec, test, match, replace, etc. 100%
TypedArray Int8Array, Float64Array, DataView, etc. 100%
Function / Error / JSON call, bind, parse, stringify, etc. 75-100%
Reflect / Proxy get, set, has, traps, etc. 69-100%
Global / Console eval, parseInt, log, error, etc. 28-100%

Integration & Development

Topic Description
Host Integration API Embedding guide: SetGlobalValue, module loaders, .NET/JS bridging
Standard Library Architecture Attribute-based prototypes, constructor patterns
Source Generator Architecture PrototypeSourceGenerator, stdlib-compat.json, automatic stubs
Performance Patterns Object pooling, fast/slow path split, caching
Debugging Logger assertions, pool guards, AST-free execution checks
Testing IR plan logging, AST node access, cache verification, test helpers

Advanced Topics

Topic Description
Error Signaling ThrowSignal vs CompletionSignal, control flow patterns
Proxy & Reflect 13 trap handlers, revocable proxies, Reflect operations
RegExp Implementation JS-to-.NET pattern translation, Unicode mode, surrogate handling
Symbol System JsSymbol vs Symbol atoms, global registry, well-known symbols
Temporal API TC39 Temporal proposal, nanosecond precision, timezone support
Pooling Deep Dive BucketedArrayPool, IsCaptured pattern, lock-free algorithms
BigInt Implementation Arbitrary precision integers, BigInteger wrapper, typed arrays
WeakCollections WeakMap, WeakSet, WeakRef - ConditionalWeakTable-based weak refs
Iterator Protocol Iterators, for-of lowering, TC39 iterator helpers

Core Concepts

Execution Model

The engine has two execution paths:

  1. IR Execution (primary) - AST is lowered to a flat instruction sequence with explicit jumps
  2. AST Walking (fallback) - Direct recursive evaluation for with/eval functions
flowchart LR
    JS[/"JS Source"/] --> Parser((Parser))
    Parser --> AST((AST))
    AST --> Analysis((Scope Analysis))
    Analysis --> Decision{with/eval?}
    Decision -->|No| IR[["IR Execution"]]
    Decision -->|Yes| Walk[["AST Walking"]]
    IR --> Result[/"JsValue"/]
    Walk --> Result
Loading

Key Types

Type Location Purpose
JsValue JsValue.cs Tagged union for JS values (undefined, null, bool, number, string, symbol, object)
JsEnvironment JsEnvironment.cs Lexical scope with variable slots
ExecutionPlan Execution/ExecutionPlan.cs Lowered IR for a function/script
ExecutionInstruction Execution/Instructions/ Base for all IR instructions
ExecutionPlanRunner TypedAstEvaluator.ExecutionPlanRunner.cs The IR interpreter
EvaluationContext EvaluationContext.cs Per-execution state (realm, signals, cancellation)

Variable Access (Three Levels)

From slowest to fastest:

Level Mechanism Use Case
Named Walk scope chain, linear scan by Symbol eval, with, unoptimized
Slot Direct index into scope's slot array Known scope, JsVariable
Flat Slot Single flat array across all scopes IR hot paths, O(1) regardless of depth

See: JsEnvironment & Slots


IR System

Lowering Pipeline

flowchart LR
    subgraph AST["AST"]
        IF((if)) --> C((x))
        IF --> T((then))
        IF --> E((else))
    end
    
    subgraph IR["IR"]
        I0["0: Branch"] --> I1["1: a()"]
        I0 -.-> I3["3: b()"]
        I1 --> I2["2: Jump"]
        I2 -.-> I4["4: ..."]
        I3 --> I4
    end
    
    AST ==> IR
Loading

Emitters

Located in Execution/Emitters/:

Emitter Handles
LoopEmitter for/while/do-while
ForOfEmitter for-of/for-in iteration
TryEmitter try/catch/finally
SwitchEmitter switch statements
YieldEmitter yield/yield*
BlockEmitter block scopes

Dispatch Table

Handlers indexed by InstructionKind enum for O(1) dispatch:

private static readonly InstructionHandler[] _dispatchTable = new InstructionHandler[43];

See: IR Execution


Function Variants

Type File Description
Sync SyncFunctionInvoker.cs Normal functions, uses IR with AST fallback
Generator SyncGeneratorInvoker.cs Pause/resume via yield, returns iterator
Async AsyncFunctionInvoker.cs Reuses generator IR, driven internally
Async Generator AsyncGeneratorInvoker.cs Iterator where .next() returns Promise

Generator Mechanics

  • YieldInstruction pauses execution, returns { value, done: false }
  • StoreResumeValue handles .next(value), .return(), .throw()
  • YieldStarInstruction delegates to inner iterator

Async Mechanics

  • await on unresolved promise sets IsPendingAwait
  • HandlePendingStep attaches .then() handlers
  • Callbacks resume via DriveToCompletion()

See: Generators & Async


Performance Patterns

Object Pooling

Pooled types (implement IRentable):

  • JsEnvironment - execution scopes
  • IteratorDriverState - for-of loop state
  • ForInDriverState - for-in loop state
  • Various enumerators

Fast/Slow Path Split

Hot handlers use inlined fast path + non-inlined slow path:

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static InstructionResult HandleIncrementSlot(...)
{
    if (flatSlotId >= 0 && _flatSlots is not null)
        return FastPath(...);  // inline

    return HandleIncrementSlotSlow(...);  // no-inline
}

Completion Signals

Control flow modeled as typed signals (not exceptions):

  • ReturnCompletionSignal
  • ThrowFlowCompletionSignal
  • BreakCompletionSignal / ContinueCompletionSignal
  • YieldCompletionSignal
  • PendingAwaitCompletionSignal

See: Performance Patterns


Debugging

Pool Debug Invariants

Two-tier system to catch pooling bugs:

Tier File Scope
PoolDebug PoolDebug.cs DEBUG-only, zero RELEASE overhead
PoolGuard PoolGuard.cs Runtime, env var JSENGINE_DEBUG_POOL_GUARDS=true

AST-Free Execution Assertion

#if DEBUG
EvaluationContext.AssertNoAstEvaluation = true;
// Throws if IR execution falls back to AST
#endif

Realm Logger

Use FakeLogger with DebugMode = true to capture slot hits/misses.

See: Debugging


Comparisons

vs Jint

Aspect Jint JsEngine
ExecutionContext Immutable struct Sealed class
Promise/Async Sync blocking Microtask queue (spec-compliant)
Property Storage HybridDictionary Standard Dictionary
Control Flow Exceptions Completion Signals
Generators AST replay IR with pause/resume

See: Jint vs JsEngine Comparison


Development

Build & Test

dotnet build
dotnet test tests/Asynkron.JsEngine.Tests

Pre-PR Checklist

  1. roslynator fix src/Asynkron.JsEngine
  2. dotnet test tests/Asynkron.JsEngine.Tests (all pass)
  3. quickdup --path src/Asynkron.JsEngine --ext .cs (no new duplications)
  4. dotnet format src/Asynkron.JsEngine

Profiling

Scripts in scripts/:

  • profile.sh - CPU profiling with dotnet-trace
  • Heap and exception profiling available

Documentation Index

Agent How-To Guides

Guide Description
Architecture Full execution model deep-dive
JsValue Usage Evaluator overload pattern
Debugging Logger assertions, pool guards
Coding Standards InvariantCulture, style rules
Development Rules Thread safety, timeouts
Build & Test Commands, demos
Profiling CPU/memory profiling
Test Bombs Systematic debugging methodology
Layered Tests Stage-by-stage verification

Docs Folder

Doc Description
Jint Comparison Architectural trade-offs
Instruction Size Audit IR instruction optimization

ECMAScript Compliance

See: Test262 README

Clone this wiki locally