Skip to content

Epic: Design: IR-only execution  #364

@rogeralsing

Description

@rogeralsing

Context

The engine currently has an IR execution plan (ExecutionPlan) and interpreter (ExecutionPlanRunner), but many IR instructions still embed AST nodes and evaluate them via EvaluateForJsValue/EvaluateExpression at runtime. The goal is to eliminate all runtime AST evaluation and optionally add a .NET IL compilation backend.

Phases 0–2 are complete: statement-level AST delegation is removed, expression bytecode is introduced, and AST evaluators are quarantined. Current progress is ~78%, with the remaining work focused on eliminating the last AST seams (captured with chains, edge-case dynamic scopes) and the future IL backend phases.

Success Criteria

Phase 1–3 (AST Elimination) — ~78% complete

  • No StatementInstruction escape hatches in emitted plans
  • IR lowering for for..in, with, block lexical environments, destructuring declarations
  • Expression bytecode replaces ExpressionNode.EvaluateExpression operands
  • AST evaluators quarantined to analysis/debug only
  • Zero AST evaluator calls during any runtime execution path (remaining: captured with chain scripts/eval, ambient with entry)
  • AssertNoAstEvaluation passes for all sync execution paths

Phase 4 — IL Backend for Sync Bytecode

  • BytecodePlan compiles to DynamicMethod delegate
  • Tiered execution: interpret first N calls, compile on hot threshold
  • Cache compiled delegates keyed by plan identity + layout id
  • Kill switch + "dynamic code supported" guard

Phase 5 — IL Backend for Generator/Async

  • Compile step function: delegate StepResult Step(ref GeneratorState state, ResumeMode mode, JsValue arg, ExecutionFrame frame)
  • Yield suspension points preserved
  • Try/finally semantics across suspension
  • Pending await plumbing

Rules

  • AST walkers must only be used for parsing + analysis, never at runtime
  • Runtime helpers must operate on JsValue/env/context, never on AST nodes
  • Interpreter fallback must always be available (IL backend is optional)
  • with-closure quarantine must remain intact for captured with environments
  • All changes must pass existing Test262 and internal test suites without regression

NFRs

  • Memory footprint must not regress (baseline: forloop --memory = 7.05 MB)
  • IL backend must have tiering to avoid compile-time overhead for cold functions
  • Debug mapping (PC → source span) must be preserved for diagnostics

Sub-Issues

Quality Gates

  • All internal unit tests pass (dotnet test tests/Asynkron.JsEngine.Tests)
  • AST-eval seam scan returns 0: rg 'EvaluateExpression\(|ProfileEvaluateExpression\(' src/Asynkron.JsEngine/Ast/TypedAstEvaluator.ExecutionPlanRunner* | wc -l
  • AssertNoAstEvaluation debug tests pass for all execution paths
  • Memory baseline maintained (./tools/profile forloop --memory ≤ 7.05 MB)
  • Test262 Language and BuiltIns runsettings show no regressions
  • No roslynator warnings in changed files

Faktoria Attribution: agent=intake | trigger=new issue intake

Metadata

Metadata

Assignees

No one assigned

    Labels

    DoingKanban status: DoingepicirIntermediate representation (IR)needs-reviewHuman decision requiredp1Importantsize:LLarge — 4+ hours, consider splittingstage:investigateAnalyzing — not coding yet

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions